nextly 0.0.1 → 0.0.2-alpha.1

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 (268) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +122 -0
  3. package/dist/_dts-chunks/collections-handler.d-DjgO74Wt.d.ts +20540 -0
  4. package/dist/_dts-chunks/config.d-DNwsDnjs.d.ts +2589 -0
  5. package/dist/_dts-chunks/define-component.d-BUgTHmt3.d.ts +1149 -0
  6. package/dist/_dts-chunks/image-processor.d-OO1PmMrv.d.ts +335 -0
  7. package/dist/_dts-chunks/index.d-axCAzZ7m.d.ts +17842 -0
  8. package/dist/_dts-chunks/media.d-DjDOZo4B.d.ts +117 -0
  9. package/dist/_dts-chunks/on-error.d-CHIKWNxd.d.ts +38 -0
  10. package/dist/_dts-chunks/storage.d-BUhQ2we_.d.ts +404 -0
  11. package/dist/actions/index.d.ts +239 -0
  12. package/dist/actions/index.mjs +281 -0
  13. package/dist/api/auth-state.d.ts +5 -0
  14. package/dist/api/auth-state.mjs +131 -0
  15. package/dist/api/collections-schema-detail.d.ts +56 -0
  16. package/dist/api/collections-schema-detail.mjs +244 -0
  17. package/dist/api/collections-schema-export.d.ts +56 -0
  18. package/dist/api/collections-schema-export.mjs +129 -0
  19. package/dist/api/collections-schema.d.ts +59 -0
  20. package/dist/api/collections-schema.mjs +207 -0
  21. package/dist/api/components-detail.d.ts +50 -0
  22. package/dist/api/components-detail.mjs +132 -0
  23. package/dist/api/components.d.ts +69 -0
  24. package/dist/api/components.mjs +144 -0
  25. package/dist/api/email-providers-default.d.ts +40 -0
  26. package/dist/api/email-providers-default.mjs +75 -0
  27. package/dist/api/email-providers-detail.d.ts +81 -0
  28. package/dist/api/email-providers-detail.mjs +109 -0
  29. package/dist/api/email-providers-test.d.ts +43 -0
  30. package/dist/api/email-providers-test.mjs +114 -0
  31. package/dist/api/email-providers.d.ts +69 -0
  32. package/dist/api/email-providers.mjs +110 -0
  33. package/dist/api/email-send-template.d.ts +41 -0
  34. package/dist/api/email-send-template.mjs +58 -0
  35. package/dist/api/email-send.d.ts +42 -0
  36. package/dist/api/email-send.mjs +58 -0
  37. package/dist/api/email-templates-detail.d.ts +74 -0
  38. package/dist/api/email-templates-detail.mjs +112 -0
  39. package/dist/api/email-templates-layout.d.ts +55 -0
  40. package/dist/api/email-templates-layout.mjs +92 -0
  41. package/dist/api/email-templates-preview.d.ts +48 -0
  42. package/dist/api/email-templates-preview.mjs +93 -0
  43. package/dist/api/email-templates.d.ts +61 -0
  44. package/dist/api/email-templates.mjs +118 -0
  45. package/dist/api/health.d.ts +68 -0
  46. package/dist/api/health.mjs +67 -0
  47. package/dist/api/index.d.ts +54 -0
  48. package/dist/api/index.mjs +16 -0
  49. package/dist/api/media-bulk.d.ts +74 -0
  50. package/dist/api/media-bulk.mjs +196 -0
  51. package/dist/api/media-folders.d.ts +112 -0
  52. package/dist/api/media-folders.mjs +187 -0
  53. package/dist/api/media-handlers.d.ts +102 -0
  54. package/dist/api/media-handlers.mjs +437 -0
  55. package/dist/api/media.d.ts +117 -0
  56. package/dist/api/media.mjs +242 -0
  57. package/dist/api/singles-detail.d.ts +87 -0
  58. package/dist/api/singles-detail.mjs +170 -0
  59. package/dist/api/singles-schema-detail.d.ts +54 -0
  60. package/dist/api/singles-schema-detail.mjs +182 -0
  61. package/dist/api/singles.d.ts +34 -0
  62. package/dist/api/singles.mjs +94 -0
  63. package/dist/api/storage-upload-url.d.ts +48 -0
  64. package/dist/api/storage-upload-url.mjs +202 -0
  65. package/dist/api/uploads.d.ts +109 -0
  66. package/dist/api/uploads.mjs +359 -0
  67. package/dist/auth/index.d.ts +425 -0
  68. package/dist/auth/index.mjs +199 -0
  69. package/dist/boot-apply-PQSYLDIN.mjs +7 -0
  70. package/dist/chunk-2OALJTK6.mjs +489 -0
  71. package/dist/chunk-2Q2SX2CS.mjs +365 -0
  72. package/dist/chunk-2TFX4ND3.mjs +13 -0
  73. package/dist/chunk-2TWPDSYD.mjs +87 -0
  74. package/dist/chunk-2W3DVD7S.mjs +647 -0
  75. package/dist/chunk-2ZFKXPQM.mjs +88 -0
  76. package/dist/chunk-3FA7FKAV.mjs +832 -0
  77. package/dist/chunk-3NZ2KMBL.mjs +58 -0
  78. package/dist/chunk-4MJLT6PZ.mjs +0 -0
  79. package/dist/chunk-56WO4WX7.mjs +0 -0
  80. package/dist/chunk-5APFUGAD.mjs +89 -0
  81. package/dist/chunk-5HMZ644B.mjs +108 -0
  82. package/dist/chunk-67GXH6PR.mjs +32 -0
  83. package/dist/chunk-6JNEPWRW.mjs +14368 -0
  84. package/dist/chunk-6NFHQIJD.mjs +45 -0
  85. package/dist/chunk-7P6ASYW6.mjs +9 -0
  86. package/dist/chunk-A3WPLSDT.mjs +1364 -0
  87. package/dist/chunk-AGJ6F2T3.mjs +144 -0
  88. package/dist/chunk-AK6Z23OX.mjs +1464 -0
  89. package/dist/chunk-APKKRD2G.mjs +102 -0
  90. package/dist/chunk-B2GV2BWH.mjs +73 -0
  91. package/dist/chunk-D5HQBNUB.mjs +74 -0
  92. package/dist/chunk-DNNG377Z.mjs +204 -0
  93. package/dist/chunk-DP3G27G5.mjs +135 -0
  94. package/dist/chunk-DV6WVX2Q.mjs +0 -0
  95. package/dist/chunk-DXGGXIUZ.mjs +57 -0
  96. package/dist/chunk-EGXBZCGC.mjs +943 -0
  97. package/dist/chunk-ERCNLX3V.mjs +176 -0
  98. package/dist/chunk-FQULBZ53.mjs +850 -0
  99. package/dist/chunk-G2AA4QLC.mjs +262 -0
  100. package/dist/chunk-GDBJ5JCU.mjs +488 -0
  101. package/dist/chunk-GJNSJU4S.mjs +19 -0
  102. package/dist/chunk-GZ6DCQKC.mjs +69 -0
  103. package/dist/chunk-H26B4FYG.mjs +167 -0
  104. package/dist/chunk-I4JMR3UR.mjs +21 -0
  105. package/dist/chunk-INV7QKLG.mjs +508 -0
  106. package/dist/chunk-IUDOC7N7.mjs +46 -0
  107. package/dist/chunk-IZWPRDC3.mjs +206 -0
  108. package/dist/chunk-KIMNCZGV.mjs +15 -0
  109. package/dist/chunk-L6HW2DA7.mjs +15 -0
  110. package/dist/chunk-LAZXX4HR.mjs +100 -0
  111. package/dist/chunk-LDKCUMHK.mjs +95 -0
  112. package/dist/chunk-LRXMECUA.mjs +0 -0
  113. package/dist/chunk-M52VMPGA.mjs +119 -0
  114. package/dist/chunk-MGUWEEI6.mjs +160 -0
  115. package/dist/chunk-NRUWQ5Z7.mjs +419 -0
  116. package/dist/chunk-NSEFNNU4.mjs +25360 -0
  117. package/dist/chunk-NTHVDFGO.mjs +138 -0
  118. package/dist/chunk-O3QHXMOX.mjs +3166 -0
  119. package/dist/chunk-P7NH2OSC.mjs +2605 -0
  120. package/dist/chunk-PKMABBB5.mjs +184 -0
  121. package/dist/chunk-PWS6XGJK.mjs +76 -0
  122. package/dist/chunk-R6JJQHFC.mjs +20 -0
  123. package/dist/chunk-RJLLGGPG.mjs +0 -0
  124. package/dist/chunk-SBACDPNX.mjs +689 -0
  125. package/dist/chunk-TO5AFLVQ.mjs +124 -0
  126. package/dist/chunk-TS7GHTG2.mjs +5436 -0
  127. package/dist/chunk-UJ2IMJ4W.mjs +133 -0
  128. package/dist/chunk-UOP63Q54.mjs +102 -0
  129. package/dist/chunk-UUOFWCM6.mjs +78 -0
  130. package/dist/chunk-V4EQTOA4.mjs +893 -0
  131. package/dist/chunk-VJ66NCL4.mjs +193 -0
  132. package/dist/chunk-VQJQHVEV.mjs +29 -0
  133. package/dist/chunk-VTJADRO3.mjs +141 -0
  134. package/dist/chunk-VWF3JO32.mjs +0 -0
  135. package/dist/chunk-W4MGXIRR.mjs +27 -0
  136. package/dist/chunk-W5KKPZT5.mjs +1204 -0
  137. package/dist/chunk-WD34YQ6T.mjs +381 -0
  138. package/dist/chunk-WZBYMYVW.mjs +14 -0
  139. package/dist/chunk-X23WKS3Z.mjs +50 -0
  140. package/dist/chunk-X7TXCYYN.mjs +6496 -0
  141. package/dist/chunk-XGI4EMS3.mjs +140 -0
  142. package/dist/chunk-XZKLBMN6.mjs +1153 -0
  143. package/dist/chunk-YB7INWPY.mjs +0 -0
  144. package/dist/chunk-YV4Y7SDL.mjs +83 -0
  145. package/dist/chunk-YZNBLFIW.mjs +1688 -0
  146. package/dist/chunk-YZZCTONM.mjs +263 -0
  147. package/dist/chunk-ZE6A3FYH.mjs +289 -0
  148. package/dist/cli/nextly.mjs +68 -0
  149. package/dist/cli/utils/index.d.ts +449 -0
  150. package/dist/cli/utils/index.mjs +49 -0
  151. package/dist/component-schema-service-5577KVW6.mjs +11 -0
  152. package/dist/config-loader-23YEMC3Z.mjs +23 -0
  153. package/dist/config.d.ts +44 -0
  154. package/dist/config.mjs +109 -0
  155. package/dist/container-ORGFGYSZ.mjs +9 -0
  156. package/dist/database/index.d.ts +12 -0
  157. package/dist/database/index.mjs +40 -0
  158. package/dist/database/seeders/index.d.ts +93 -0
  159. package/dist/database/seeders/index.mjs +47 -0
  160. package/dist/db-sync-demote-LJGKLB3S.mjs +117 -0
  161. package/dist/db-sync-promote-B26VSYQF.mjs +113 -0
  162. package/dist/dev-reload-broadcaster-B73IQ53V.mjs +25 -0
  163. package/dist/dist-M2NOU37V.mjs +19 -0
  164. package/dist/drizzle-kit-lazy-D2M2PXR2.mjs +13 -0
  165. package/dist/dynamic-collection-schema-service-IEXTPIZ7.mjs +8 -0
  166. package/dist/errors/index.d.ts +159 -0
  167. package/dist/errors/index.mjs +10 -0
  168. package/dist/factory-IWMBKUJM.mjs +15 -0
  169. package/dist/first-run-QIVKWJIF.mjs +63 -0
  170. package/dist/fresh-push-NR67DC3R.mjs +8 -0
  171. package/dist/index.d.ts +4175 -0
  172. package/dist/index.mjs +1336 -0
  173. package/dist/local-plugin-PTET4NAT.mjs +7 -0
  174. package/dist/logger-NU46DXNY.mjs +15 -0
  175. package/dist/logger-YE4TC7ZN.mjs +9 -0
  176. package/dist/migration-journal-EP532Y4L.mjs +139 -0
  177. package/dist/migrations/mysql/0000_eager_sentry.sql +174 -0
  178. package/dist/migrations/mysql/0001_soft_giant_girl.sql +27 -0
  179. package/dist/migrations/mysql/0002_media_table.sql +24 -0
  180. package/dist/migrations/mysql/0003_dynamic_singles.sql +37 -0
  181. package/dist/migrations/mysql/0004_dynamic_components.sql +35 -0
  182. package/dist/migrations/mysql/0005_user_management_tables.sql +92 -0
  183. package/dist/migrations/mysql/0006_api_keys.sql +36 -0
  184. package/dist/migrations/mysql/0007_general_settings.sql +20 -0
  185. package/dist/migrations/mysql/0008_site_settings_logo_url.sql +9 -0
  186. package/dist/migrations/mysql/0009_activity_log.sql +30 -0
  187. package/dist/migrations/mysql/0010_site_settings_sidebar.sql +13 -0
  188. package/dist/migrations/mysql/0011_missing_tables_and_columns.sql +54 -0
  189. package/dist/migrations/mysql/0012_image_sizes_and_focal_point.sql +30 -0
  190. package/dist/migrations/mysql/0012_media_folders.sql +43 -0
  191. package/dist/migrations/mysql/0013_user_brute_force_protection.sql +31 -0
  192. package/dist/migrations/mysql/0014_email_template_attachments.sql +12 -0
  193. package/dist/migrations/mysql/0015_media_uploaded_by_nullable.sql +15 -0
  194. package/dist/migrations/mysql/20260429_000000_000_initial_journal.sql +22 -0
  195. package/dist/migrations/mysql/20260501_000000_journal_batch.sql +17 -0
  196. package/dist/migrations/mysql/20260501_000001_audit_log.sql +24 -0
  197. package/dist/migrations/mysql/20260504_000000_nextly_meta.sql +21 -0
  198. package/dist/migrations/mysql/meta/0000_snapshot.json +1005 -0
  199. package/dist/migrations/mysql/meta/0001_snapshot.json +1099 -0
  200. package/dist/migrations/mysql/meta/_journal.json +41 -0
  201. package/dist/migrations/postgresql/0000_misty_king_bedlam.sql +169 -0
  202. package/dist/migrations/postgresql/0001_perpetual_captain_marvel.sql +8 -0
  203. package/dist/migrations/postgresql/0002_sad_spectrum.sql +16 -0
  204. package/dist/migrations/postgresql/0003_hesitant_ultron.sql +17 -0
  205. package/dist/migrations/postgresql/0004_media_table.sql +24 -0
  206. package/dist/migrations/postgresql/0005_media_folders.sql +36 -0
  207. package/dist/migrations/postgresql/0006_dynamic_collections_update.sql +50 -0
  208. package/dist/migrations/postgresql/0007_dynamic_singles.sql +38 -0
  209. package/dist/migrations/postgresql/0008_dynamic_components.sql +37 -0
  210. package/dist/migrations/postgresql/0009_user_management_tables.sql +95 -0
  211. package/dist/migrations/postgresql/0010_api_keys.sql +34 -0
  212. package/dist/migrations/postgresql/0011_general_settings.sql +20 -0
  213. package/dist/migrations/postgresql/0012_site_settings_logo_url.sql +9 -0
  214. package/dist/migrations/postgresql/0013_activity_log.sql +29 -0
  215. package/dist/migrations/postgresql/0014_image_sizes_and_focal_point.sql +33 -0
  216. package/dist/migrations/postgresql/0014_site_settings_sidebar.sql +13 -0
  217. package/dist/migrations/postgresql/0015_user_brute_force_protection.sql +29 -0
  218. package/dist/migrations/postgresql/0016_email_template_attachments.sql +12 -0
  219. package/dist/migrations/postgresql/0017_media_uploaded_by_nullable.sql +15 -0
  220. package/dist/migrations/postgresql/20260429_000000_000_initial_journal.sql +24 -0
  221. package/dist/migrations/postgresql/20260501_000000_journal_batch.sql +17 -0
  222. package/dist/migrations/postgresql/20260501_000001_audit_log.sql +24 -0
  223. package/dist/migrations/postgresql/20260504_000000_nextly_meta.sql +22 -0
  224. package/dist/migrations/postgresql/meta/0000_snapshot.json +1286 -0
  225. package/dist/migrations/postgresql/meta/0001_snapshot.json +1407 -0
  226. package/dist/migrations/postgresql/meta/0002_snapshot.json +1552 -0
  227. package/dist/migrations/postgresql/meta/0003_snapshot.json +1695 -0
  228. package/dist/migrations/postgresql/meta/0010_snapshot.json +2345 -0
  229. package/dist/migrations/postgresql/meta/_journal.json +90 -0
  230. package/dist/migrations/sqlite/0000_api_keys.sql +34 -0
  231. package/dist/migrations/sqlite/0001_general_settings.sql +20 -0
  232. package/dist/migrations/sqlite/0002_site_settings_logo_url.sql +9 -0
  233. package/dist/migrations/sqlite/0003_activity_log.sql +29 -0
  234. package/dist/migrations/sqlite/0004_image_sizes_and_focal_point.sql +29 -0
  235. package/dist/migrations/sqlite/0004_site_settings_sidebar.sql +11 -0
  236. package/dist/migrations/sqlite/0005_user_brute_force_protection.sql +29 -0
  237. package/dist/migrations/sqlite/0006_email_template_attachments.sql +12 -0
  238. package/dist/migrations/sqlite/0007_media_uploaded_by_nullable.sql +111 -0
  239. package/dist/migrations/sqlite/20260429_000000_000_initial_journal.sql +24 -0
  240. package/dist/migrations/sqlite/20260501_000000_journal_batch.sql +19 -0
  241. package/dist/migrations/sqlite/20260501_000001_audit_log.sql +24 -0
  242. package/dist/migrations/sqlite/20260504_000000_nextly_meta.sql +21 -0
  243. package/dist/migrations/sqlite/20260505_000000_user_management_tables.sql +77 -0
  244. package/dist/next.d.ts +57 -0
  245. package/dist/next.mjs +55 -0
  246. package/dist/observability/index.d.ts +87 -0
  247. package/dist/observability/index.mjs +57 -0
  248. package/dist/permissions-3DZZQZMI.mjs +39 -0
  249. package/dist/pipeline-YOML7SWF.mjs +29 -0
  250. package/dist/preview-ZZTR3QGS.mjs +9 -0
  251. package/dist/program-PW6UB2ZC.mjs +5934 -0
  252. package/dist/reconcile-single-tables-7ENVXJGB.mjs +7 -0
  253. package/dist/register-SF6E6FVU.mjs +49 -0
  254. package/dist/reload-config-HWQ4G5MM.mjs +23 -0
  255. package/dist/resolve-single-table-name-JSOMUB3R.mjs +7 -0
  256. package/dist/routeHandler-UNMMJIBM.mjs +77 -0
  257. package/dist/runtime-schema-generator-NRA6A6Z6.mjs +8 -0
  258. package/dist/runtime.d.ts +120 -0
  259. package/dist/runtime.mjs +73 -0
  260. package/dist/schema-hash-FMMG6VPJ.mjs +13 -0
  261. package/dist/schema-registry-EQ36FZDP.mjs +7 -0
  262. package/dist/scripts/load-env.mjs +42 -0
  263. package/dist/storage/index.d.ts +566 -0
  264. package/dist/storage/index.mjs +45 -0
  265. package/dist/super-admin-G5ZK5F4T.mjs +39 -0
  266. package/dist/system-table-service-WGSRVEGT.mjs +17 -0
  267. package/dist/users-7KELGRYJ.mjs +38 -0
  268. package/package.json +308 -9
@@ -0,0 +1,244 @@
1
+ import "../chunk-LRXMECUA.mjs";
2
+ import {
3
+ getSession
4
+ } from "../chunk-UUOFWCM6.mjs";
5
+ import "../chunk-VWF3JO32.mjs";
6
+ import "../chunk-2ZFKXPQM.mjs";
7
+ import {
8
+ withErrorHandler
9
+ } from "../chunk-TO5AFLVQ.mjs";
10
+ import {
11
+ getCachedNextly
12
+ } from "../chunk-P7NH2OSC.mjs";
13
+ import "../chunk-2OALJTK6.mjs";
14
+ import "../chunk-VJ66NCL4.mjs";
15
+ import "../chunk-R6JJQHFC.mjs";
16
+ import "../chunk-X23WKS3Z.mjs";
17
+ import {
18
+ getService
19
+ } from "../chunk-X7TXCYYN.mjs";
20
+ import "../chunk-YZNBLFIW.mjs";
21
+ import "../chunk-FQULBZ53.mjs";
22
+ import "../chunk-67GXH6PR.mjs";
23
+ import "../chunk-2TFX4ND3.mjs";
24
+ import {
25
+ getNextlyLogger
26
+ } from "../chunk-W4MGXIRR.mjs";
27
+ import "../chunk-NSEFNNU4.mjs";
28
+ import "../chunk-3FA7FKAV.mjs";
29
+ import "../chunk-AGJ6F2T3.mjs";
30
+ import "../chunk-KIMNCZGV.mjs";
31
+ import "../chunk-AK6Z23OX.mjs";
32
+ import "../chunk-INV7QKLG.mjs";
33
+ import "../chunk-GZ6DCQKC.mjs";
34
+ import "../chunk-SBACDPNX.mjs";
35
+ import "../chunk-RJLLGGPG.mjs";
36
+ import "../chunk-V4EQTOA4.mjs";
37
+ import "../chunk-I4JMR3UR.mjs";
38
+ import "../chunk-XZKLBMN6.mjs";
39
+ import "../chunk-IZWPRDC3.mjs";
40
+ import "../chunk-DNNG377Z.mjs";
41
+ import {
42
+ calculateSchemaHash
43
+ } from "../chunk-5HMZ644B.mjs";
44
+ import {
45
+ hasPermission,
46
+ isSuperAdmin
47
+ } from "../chunk-W5KKPZT5.mjs";
48
+ import "../chunk-56WO4WX7.mjs";
49
+ import "../chunk-2W3DVD7S.mjs";
50
+ import "../chunk-TS7GHTG2.mjs";
51
+ import "../chunk-H26B4FYG.mjs";
52
+ import "../chunk-DP3G27G5.mjs";
53
+ import "../chunk-DV6WVX2Q.mjs";
54
+ import {
55
+ env
56
+ } from "../chunk-UJ2IMJ4W.mjs";
57
+ import "../chunk-EGXBZCGC.mjs";
58
+ import "../chunk-G2AA4QLC.mjs";
59
+ import "../chunk-4MJLT6PZ.mjs";
60
+ import {
61
+ respondDoc,
62
+ respondMutation
63
+ } from "../chunk-IUDOC7N7.mjs";
64
+ import "../chunk-LAZXX4HR.mjs";
65
+ import "../chunk-D5HQBNUB.mjs";
66
+ import {
67
+ NextlyError
68
+ } from "../chunk-NRUWQ5Z7.mjs";
69
+ import {
70
+ simplePluralize
71
+ } from "../chunk-VTJADRO3.mjs";
72
+ import "../chunk-5APFUGAD.mjs";
73
+ import "../chunk-7P6ASYW6.mjs";
74
+
75
+ // src/api/collections-schema-detail.ts
76
+ async function getCollectionRegistry() {
77
+ await getCachedNextly();
78
+ return getService("collectionRegistryService");
79
+ }
80
+ async function getComponentRegistry() {
81
+ await getCachedNextly();
82
+ return getService("componentRegistryService");
83
+ }
84
+ async function requireUser(request) {
85
+ const result = await getSession(request, env.NEXTLY_SECRET || "");
86
+ const user = result.authenticated ? result.user : null;
87
+ if (!user) {
88
+ throw NextlyError.authRequired();
89
+ }
90
+ return { id: user.id };
91
+ }
92
+ async function requireManageSettings(userId) {
93
+ if (await isSuperAdmin(userId)) return;
94
+ const canManage = await hasPermission(userId, "manage", "settings");
95
+ if (!canManage) {
96
+ throw NextlyError.forbidden({
97
+ logContext: {
98
+ userId,
99
+ required: "manage-settings",
100
+ operation: "manage-collection"
101
+ }
102
+ });
103
+ }
104
+ }
105
+ var GET = withErrorHandler(
106
+ async (request, context) => {
107
+ const user = await requireUser(request);
108
+ const { slug } = await context.params;
109
+ const isAdmin = await isSuperAdmin(user.id);
110
+ if (!isAdmin) {
111
+ const canRead = await hasPermission(user.id, "read", slug);
112
+ if (!canRead) {
113
+ throw NextlyError.forbidden({
114
+ logContext: {
115
+ userId: user.id,
116
+ required: `read-${slug}`,
117
+ operation: "read-collection"
118
+ }
119
+ });
120
+ }
121
+ }
122
+ const registry = await getCollectionRegistry();
123
+ const collection = await registry.getCollection(slug);
124
+ let enrichedFields = collection.fields;
125
+ try {
126
+ const componentRegistry = await getComponentRegistry();
127
+ enrichedFields = await componentRegistry.enrichFieldsWithComponentSchemas(
128
+ collection.fields
129
+ );
130
+ } catch (enrichError) {
131
+ getNextlyLogger().warn({
132
+ kind: "collection-schema-enrichment-failed",
133
+ slug,
134
+ err: String(enrichError)
135
+ });
136
+ }
137
+ return respondDoc({
138
+ ...collection,
139
+ fields: enrichedFields
140
+ });
141
+ }
142
+ );
143
+ var PATCH = withErrorHandler(
144
+ async (request, context) => {
145
+ const registry = await getCollectionRegistry();
146
+ const user = await requireUser(request);
147
+ await requireManageSettings(user.id);
148
+ const { slug } = await context.params;
149
+ let body;
150
+ try {
151
+ body = await request.json();
152
+ } catch {
153
+ throw NextlyError.validation({
154
+ errors: [
155
+ {
156
+ path: "",
157
+ code: "invalid_json",
158
+ message: "Request body is not valid JSON."
159
+ }
160
+ ]
161
+ });
162
+ }
163
+ const updateData = {};
164
+ if (body.labels !== void 0) {
165
+ const labels = body.labels;
166
+ if (labels.singular !== void 0) {
167
+ const singular = labels.singular.trim();
168
+ updateData.labels = {
169
+ singular,
170
+ plural: labels.plural?.trim() || simplePluralize(singular)
171
+ };
172
+ } else {
173
+ updateData.labels = labels;
174
+ }
175
+ }
176
+ if (body.description !== void 0) {
177
+ updateData.description = body.description;
178
+ }
179
+ if (body.fields !== void 0) {
180
+ updateData.fields = body.fields;
181
+ updateData.schemaHash = calculateSchemaHash(
182
+ body.fields
183
+ );
184
+ }
185
+ if (body.timestamps !== void 0) {
186
+ updateData.timestamps = body.timestamps;
187
+ }
188
+ if (body.status !== void 0) {
189
+ updateData.status = body.status === true;
190
+ }
191
+ const ADMIN_KEYS = [
192
+ "icon",
193
+ "group",
194
+ "order",
195
+ "sidebarGroup",
196
+ "hidden",
197
+ "useAsTitle",
198
+ "defaultColumns"
199
+ ];
200
+ const adminOverrides = {};
201
+ if (body.admin !== void 0) {
202
+ const admin = body.admin;
203
+ for (const key of ADMIN_KEYS) {
204
+ if (admin[key] !== void 0) {
205
+ adminOverrides[key] = admin[key];
206
+ }
207
+ }
208
+ }
209
+ for (const key of ADMIN_KEYS) {
210
+ if (body[key] !== void 0) {
211
+ adminOverrides[key] = body[key];
212
+ }
213
+ }
214
+ if (Object.keys(adminOverrides).length > 0) {
215
+ const existing = await registry.getCollection(slug);
216
+ updateData.admin = {
217
+ ...existing.admin || {},
218
+ ...adminOverrides
219
+ };
220
+ }
221
+ if (body.hooks !== void 0) {
222
+ updateData.hooks = body.hooks;
223
+ }
224
+ const updated = await registry.updateCollection(slug, updateData, {
225
+ source: "ui"
226
+ });
227
+ return respondMutation("Collection updated.", updated);
228
+ }
229
+ );
230
+ var DELETE = withErrorHandler(
231
+ async (request, context) => {
232
+ const registry = await getCollectionRegistry();
233
+ const user = await requireUser(request);
234
+ await requireManageSettings(user.id);
235
+ const { slug } = await context.params;
236
+ await registry.deleteCollection(slug);
237
+ return new Response(null, { status: 204 });
238
+ }
239
+ );
240
+ export {
241
+ DELETE,
242
+ GET,
243
+ PATCH
244
+ };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Collection Schema Export API Route Handler for Next.js
3
+ *
4
+ * This route handler can be re-exported in your Next.js application to provide
5
+ * collection export endpoints at /api/collections/schema/[slug]/export.
6
+ *
7
+ * Exports UI-created collections to code-first format (defineCollection syntax)
8
+ * for version control and customization.
9
+ *
10
+ * Services are auto-initialized on first request using environment variables:
11
+ * - DB_DIALECT: Database dialect ("postgresql" | "mysql" | "sqlite")
12
+ * - DATABASE_URL: Database connection string
13
+ *
14
+ * The JSON path returns `{ code }` via `respondData`; the `?download=true`
15
+ * path returns the raw code as `text/plain` with a `Content-Disposition`
16
+ * attachment header (binary/text-stream responses bypass JSON envelopes).
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * // In your Next.js app: app/api/collections/schema/[slug]/export/route.ts
21
+ * export { GET } from 'nextly/api/collections-schema-export';
22
+ * ```
23
+ *
24
+ * @module api/collections-schema-export
25
+ */
26
+ /**
27
+ * Context object for dynamic route handlers.
28
+ * Next.js 15+ requires params to be a Promise.
29
+ */
30
+ interface RouteContext {
31
+ params: Promise<{
32
+ slug: string;
33
+ }>;
34
+ }
35
+ /**
36
+ * GET handler for exporting a collection to code-first format.
37
+ *
38
+ * Requires authentication and read permission for the collection.
39
+ * Generates `defineCollection()` code from the collection's field config.
40
+ *
41
+ * Query Parameters:
42
+ * - includeAccess: Include access control placeholder comments (default: true)
43
+ * - includeHooks: Include hooks placeholder comments (default: true)
44
+ * - format: Output format - "typescript" or "javascript" (default: "typescript")
45
+ * - download: If "true", returns as downloadable file instead of JSON
46
+ *
47
+ * Response Codes:
48
+ * - 200 OK: Code generated successfully (JSON or file download)
49
+ * - 401 Unauthorized: Authentication required
50
+ * - 403 Forbidden: Caller lacks read permission for this collection
51
+ * - 404 Not Found: Collection with slug does not exist
52
+ * - 500 Internal Server Error: Export failed
53
+ */
54
+ declare const GET: (request: Request, context: RouteContext) => Promise<Response>;
55
+
56
+ export { GET };
@@ -0,0 +1,129 @@
1
+ import "../chunk-LRXMECUA.mjs";
2
+ import {
3
+ getSession
4
+ } from "../chunk-UUOFWCM6.mjs";
5
+ import "../chunk-VWF3JO32.mjs";
6
+ import "../chunk-2ZFKXPQM.mjs";
7
+ import {
8
+ withErrorHandler
9
+ } from "../chunk-TO5AFLVQ.mjs";
10
+ import {
11
+ getCachedNextly
12
+ } from "../chunk-P7NH2OSC.mjs";
13
+ import "../chunk-2OALJTK6.mjs";
14
+ import "../chunk-VJ66NCL4.mjs";
15
+ import "../chunk-R6JJQHFC.mjs";
16
+ import "../chunk-X23WKS3Z.mjs";
17
+ import {
18
+ getService
19
+ } from "../chunk-X7TXCYYN.mjs";
20
+ import "../chunk-YZNBLFIW.mjs";
21
+ import "../chunk-FQULBZ53.mjs";
22
+ import "../chunk-67GXH6PR.mjs";
23
+ import "../chunk-2TFX4ND3.mjs";
24
+ import "../chunk-W4MGXIRR.mjs";
25
+ import {
26
+ CollectionExportService
27
+ } from "../chunk-NSEFNNU4.mjs";
28
+ import "../chunk-3FA7FKAV.mjs";
29
+ import "../chunk-AGJ6F2T3.mjs";
30
+ import "../chunk-KIMNCZGV.mjs";
31
+ import "../chunk-AK6Z23OX.mjs";
32
+ import "../chunk-INV7QKLG.mjs";
33
+ import "../chunk-GZ6DCQKC.mjs";
34
+ import "../chunk-SBACDPNX.mjs";
35
+ import "../chunk-RJLLGGPG.mjs";
36
+ import "../chunk-V4EQTOA4.mjs";
37
+ import "../chunk-I4JMR3UR.mjs";
38
+ import "../chunk-XZKLBMN6.mjs";
39
+ import "../chunk-IZWPRDC3.mjs";
40
+ import "../chunk-DNNG377Z.mjs";
41
+ import "../chunk-5HMZ644B.mjs";
42
+ import {
43
+ hasPermission,
44
+ isSuperAdmin
45
+ } from "../chunk-W5KKPZT5.mjs";
46
+ import "../chunk-56WO4WX7.mjs";
47
+ import "../chunk-2W3DVD7S.mjs";
48
+ import "../chunk-TS7GHTG2.mjs";
49
+ import "../chunk-H26B4FYG.mjs";
50
+ import "../chunk-DP3G27G5.mjs";
51
+ import "../chunk-DV6WVX2Q.mjs";
52
+ import {
53
+ env
54
+ } from "../chunk-UJ2IMJ4W.mjs";
55
+ import "../chunk-EGXBZCGC.mjs";
56
+ import "../chunk-G2AA4QLC.mjs";
57
+ import "../chunk-4MJLT6PZ.mjs";
58
+ import {
59
+ respondData
60
+ } from "../chunk-IUDOC7N7.mjs";
61
+ import "../chunk-LAZXX4HR.mjs";
62
+ import "../chunk-D5HQBNUB.mjs";
63
+ import {
64
+ NextlyError
65
+ } from "../chunk-NRUWQ5Z7.mjs";
66
+ import "../chunk-VTJADRO3.mjs";
67
+ import "../chunk-5APFUGAD.mjs";
68
+ import "../chunk-7P6ASYW6.mjs";
69
+
70
+ // src/api/collections-schema-export.ts
71
+ async function getCollectionRegistry() {
72
+ await getCachedNextly();
73
+ return getService("collectionRegistryService");
74
+ }
75
+ async function requireUser(request) {
76
+ const result = await getSession(request, env.NEXTLY_SECRET || "");
77
+ const user = result.authenticated ? result.user : null;
78
+ if (!user) {
79
+ throw NextlyError.authRequired();
80
+ }
81
+ return { id: user.id };
82
+ }
83
+ var GET = withErrorHandler(
84
+ async (request, context) => {
85
+ const user = await requireUser(request);
86
+ const { slug } = await context.params;
87
+ const isAdmin = await isSuperAdmin(user.id);
88
+ if (!isAdmin) {
89
+ const canRead = await hasPermission(user.id, "read", slug);
90
+ if (!canRead) {
91
+ throw NextlyError.forbidden({
92
+ logContext: {
93
+ userId: user.id,
94
+ required: `read-${slug}`,
95
+ operation: "export-collection"
96
+ }
97
+ });
98
+ }
99
+ }
100
+ const registry = await getCollectionRegistry();
101
+ const collection = await registry.getCollection(slug);
102
+ const { searchParams } = new URL(request.url);
103
+ const includeAccessPlaceholders = searchParams.get("includeAccess") !== "false";
104
+ const includeHooksPlaceholders = searchParams.get("includeHooks") !== "false";
105
+ const format = searchParams.get("format") || "typescript";
106
+ const download = searchParams.get("download") === "true";
107
+ const exportService = new CollectionExportService();
108
+ const code = exportService.exportToCode(collection, {
109
+ includeAccessPlaceholders,
110
+ includeHooksPlaceholders,
111
+ format
112
+ });
113
+ if (download) {
114
+ const extension = format === "typescript" ? ".ts" : ".js";
115
+ const filename = `${slug}${extension}`;
116
+ return new Response(code, {
117
+ status: 200,
118
+ headers: {
119
+ "Content-Type": "text/plain; charset=utf-8",
120
+ "Content-Disposition": `attachment; filename="${filename}"`
121
+ }
122
+ });
123
+ }
124
+ return respondData({ code });
125
+ }
126
+ );
127
+ export {
128
+ GET
129
+ };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Collection Schema API Route Handlers for Next.js
3
+ *
4
+ * These route handlers can be re-exported in your Next.js application to provide
5
+ * collection schema management endpoints at /api/collections/schema.
6
+ *
7
+ * Services are auto-initialized on first request using environment variables:
8
+ * - DB_DIALECT: Database dialect ("postgresql" | "mysql" | "sqlite")
9
+ * - DATABASE_URL: Database connection string
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * // In your Next.js app: app/api/collections/schema/route.ts
14
+ * export { GET, POST } from 'nextly/api/collections-schema';
15
+ * ```
16
+ *
17
+ * @module api/collections-schema
18
+ */
19
+ /**
20
+ * GET handler for listing collections with pagination and filters.
21
+ *
22
+ * Returns only collections the caller has read permission for; super-admins
23
+ * see everything. Anonymous callers get 401.
24
+ *
25
+ * Query Parameters:
26
+ * - source: Filter by source type ("code" | "ui" | "built-in")
27
+ * - search: Search query for slug and labels
28
+ * - limit: Maximum results (default: 50)
29
+ * - offset: Number of results to skip (default: 0)
30
+ *
31
+ * Response Codes:
32
+ * - 200 OK: Collections list retrieved successfully
33
+ * - 401 Unauthorized: Authentication required
34
+ * - 500 Internal Server Error: Failed to fetch collections
35
+ *
36
+ * @example
37
+ * ```bash
38
+ * curl "http://localhost:3000/api/collections/schema?source=ui&limit=10"
39
+ * # => {"items":[...],"meta":{"total":5,"page":1,"limit":10,"totalPages":1,"hasNext":false,"hasPrev":false}}
40
+ * ```
41
+ */
42
+ declare const GET: (request: Request) => Promise<Response>;
43
+ /**
44
+ * POST handler for creating a new UI collection.
45
+ *
46
+ * Requires super-admin or `manage-settings` permission. Creates a new
47
+ * collection with `source="ui"` and `locked=false`.
48
+ *
49
+ * Response Codes:
50
+ * - 201 Created: Collection created successfully
51
+ * - 400 Bad Request: Invalid input
52
+ * - 401 Unauthorized: Authentication required
53
+ * - 403 Forbidden: Caller lacks permission to create collections
54
+ * - 409 Conflict: Collection with slug already exists
55
+ * - 500 Internal Server Error: Creation failed
56
+ */
57
+ declare const POST: (request: Request) => Promise<Response>;
58
+
59
+ export { GET, POST };
@@ -0,0 +1,207 @@
1
+ import {
2
+ nextlyValidationFromZod
3
+ } from "../chunk-GJNSJU4S.mjs";
4
+ import "../chunk-LRXMECUA.mjs";
5
+ import {
6
+ getSession
7
+ } from "../chunk-UUOFWCM6.mjs";
8
+ import "../chunk-VWF3JO32.mjs";
9
+ import "../chunk-2ZFKXPQM.mjs";
10
+ import {
11
+ withErrorHandler
12
+ } from "../chunk-TO5AFLVQ.mjs";
13
+ import {
14
+ getCachedNextly
15
+ } from "../chunk-P7NH2OSC.mjs";
16
+ import "../chunk-2OALJTK6.mjs";
17
+ import "../chunk-VJ66NCL4.mjs";
18
+ import "../chunk-R6JJQHFC.mjs";
19
+ import "../chunk-X23WKS3Z.mjs";
20
+ import {
21
+ getService
22
+ } from "../chunk-X7TXCYYN.mjs";
23
+ import "../chunk-YZNBLFIW.mjs";
24
+ import "../chunk-FQULBZ53.mjs";
25
+ import "../chunk-67GXH6PR.mjs";
26
+ import "../chunk-2TFX4ND3.mjs";
27
+ import "../chunk-W4MGXIRR.mjs";
28
+ import "../chunk-NSEFNNU4.mjs";
29
+ import "../chunk-3FA7FKAV.mjs";
30
+ import "../chunk-AGJ6F2T3.mjs";
31
+ import "../chunk-KIMNCZGV.mjs";
32
+ import "../chunk-AK6Z23OX.mjs";
33
+ import "../chunk-INV7QKLG.mjs";
34
+ import "../chunk-GZ6DCQKC.mjs";
35
+ import "../chunk-SBACDPNX.mjs";
36
+ import "../chunk-RJLLGGPG.mjs";
37
+ import "../chunk-V4EQTOA4.mjs";
38
+ import "../chunk-I4JMR3UR.mjs";
39
+ import "../chunk-XZKLBMN6.mjs";
40
+ import "../chunk-IZWPRDC3.mjs";
41
+ import "../chunk-DNNG377Z.mjs";
42
+ import {
43
+ calculateSchemaHash
44
+ } from "../chunk-5HMZ644B.mjs";
45
+ import {
46
+ hasPermission,
47
+ isSuperAdmin
48
+ } from "../chunk-W5KKPZT5.mjs";
49
+ import "../chunk-56WO4WX7.mjs";
50
+ import "../chunk-2W3DVD7S.mjs";
51
+ import "../chunk-TS7GHTG2.mjs";
52
+ import "../chunk-H26B4FYG.mjs";
53
+ import "../chunk-DP3G27G5.mjs";
54
+ import "../chunk-DV6WVX2Q.mjs";
55
+ import {
56
+ env
57
+ } from "../chunk-UJ2IMJ4W.mjs";
58
+ import "../chunk-EGXBZCGC.mjs";
59
+ import "../chunk-G2AA4QLC.mjs";
60
+ import "../chunk-4MJLT6PZ.mjs";
61
+ import {
62
+ respondList,
63
+ respondMutation
64
+ } from "../chunk-IUDOC7N7.mjs";
65
+ import "../chunk-LAZXX4HR.mjs";
66
+ import "../chunk-D5HQBNUB.mjs";
67
+ import {
68
+ NextlyError
69
+ } from "../chunk-NRUWQ5Z7.mjs";
70
+ import {
71
+ simplePluralize
72
+ } from "../chunk-VTJADRO3.mjs";
73
+ import "../chunk-5APFUGAD.mjs";
74
+ import "../chunk-7P6ASYW6.mjs";
75
+
76
+ // src/api/collections-schema.ts
77
+ import { z } from "zod";
78
+ async function getCollectionRegistry() {
79
+ await getCachedNextly();
80
+ return getService("collectionRegistryService");
81
+ }
82
+ var createCollectionSchema = z.object({
83
+ slug: z.string().min(1, "Slug is required").max(255, "Slug must be 255 characters or less").regex(
84
+ /^[a-z][a-z0-9_]*$/,
85
+ "Slug must start with a letter and contain only lowercase letters, numbers, and underscores"
86
+ ),
87
+ labels: z.object({
88
+ singular: z.string().trim().min(1, "Singular label is required"),
89
+ plural: z.string().trim().min(1, "Plural label is required").optional()
90
+ }),
91
+ description: z.string().optional(),
92
+ fields: z.array(z.any()),
93
+ // Field validation is complex, handled by service
94
+ timestamps: z.boolean().default(true),
95
+ // Draft/Published opt-in. Default false keeps the existing public API
96
+ // contract — collections without the flag continue to ship a single
97
+ // Save/Create button.
98
+ status: z.boolean().optional(),
99
+ admin: z.object({
100
+ group: z.string().optional(),
101
+ icon: z.string().optional(),
102
+ hidden: z.boolean().optional(),
103
+ useAsTitle: z.string().optional(),
104
+ isPlugin: z.boolean().optional(),
105
+ order: z.number().optional(),
106
+ sidebarGroup: z.string().optional()
107
+ }).optional(),
108
+ hooks: z.array(z.any()).optional()
109
+ });
110
+ async function requireUser(request) {
111
+ const result = await getSession(request, env.NEXTLY_SECRET || "");
112
+ const user = result.authenticated ? result.user : null;
113
+ if (!user) {
114
+ throw NextlyError.authRequired();
115
+ }
116
+ return { id: user.id };
117
+ }
118
+ var GET = withErrorHandler(async (request) => {
119
+ const user = await requireUser(request);
120
+ const registry = await getCollectionRegistry();
121
+ const { searchParams } = new URL(request.url);
122
+ const source = searchParams.get("source");
123
+ const search = searchParams.get("search") || void 0;
124
+ const limit = searchParams.get("limit") ? parseInt(searchParams.get("limit"), 10) : 50;
125
+ const offset = searchParams.get("offset") ? parseInt(searchParams.get("offset"), 10) : 0;
126
+ const result = await registry.listCollections({
127
+ source: source || void 0,
128
+ search,
129
+ limit,
130
+ offset
131
+ });
132
+ const isAdmin = await isSuperAdmin(user.id);
133
+ let filteredCollections = result.data;
134
+ if (!isAdmin) {
135
+ const permittedCollections = [];
136
+ for (const collection of result.data) {
137
+ const collectionSlug = collection.slug;
138
+ const canRead = await hasPermission(user.id, "read", collectionSlug);
139
+ if (canRead) {
140
+ permittedCollections.push(collection);
141
+ }
142
+ }
143
+ filteredCollections = permittedCollections;
144
+ }
145
+ const safeLimit = Math.max(1, limit);
146
+ const page = Math.floor(offset / safeLimit) + 1;
147
+ const total = filteredCollections.length;
148
+ const totalPages = Math.ceil(total / safeLimit);
149
+ return respondList(filteredCollections, {
150
+ total,
151
+ page,
152
+ limit: safeLimit,
153
+ totalPages,
154
+ hasNext: page < totalPages,
155
+ hasPrev: page > 1
156
+ });
157
+ });
158
+ var POST = withErrorHandler(async (request) => {
159
+ const user = await requireUser(request);
160
+ const registry = await getCollectionRegistry();
161
+ const isAdmin = await isSuperAdmin(user.id);
162
+ if (!isAdmin) {
163
+ const canManage = await hasPermission(user.id, "manage", "settings");
164
+ if (!canManage) {
165
+ throw NextlyError.forbidden({
166
+ logContext: {
167
+ userId: user.id,
168
+ required: "manage-settings",
169
+ operation: "create-collection"
170
+ }
171
+ });
172
+ }
173
+ }
174
+ const body = await request.json();
175
+ const parseResult = createCollectionSchema.safeParse(body);
176
+ if (!parseResult.success) {
177
+ throw nextlyValidationFromZod(parseResult.error);
178
+ }
179
+ const validated = parseResult.data;
180
+ const tableName = validated.slug.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
181
+ const schemaHash = calculateSchemaHash(validated.fields);
182
+ const normalizedLabels = {
183
+ singular: validated.labels.singular.trim(),
184
+ plural: validated.labels.plural?.trim() || simplePluralize(validated.labels.singular)
185
+ };
186
+ const collection = await registry.registerCollection({
187
+ slug: validated.slug,
188
+ labels: normalizedLabels,
189
+ tableName,
190
+ description: validated.description,
191
+ fields: validated.fields,
192
+ timestamps: validated.timestamps,
193
+ admin: validated.admin,
194
+ source: "ui",
195
+ locked: false,
196
+ // Forward Draft/Published flag so the schema-level POST honours the
197
+ // user's status opt-in just like the dispatcher path does.
198
+ status: validated.status === true,
199
+ schemaHash,
200
+ hooks: validated.hooks
201
+ });
202
+ return respondMutation("Collection created.", collection, { status: 201 });
203
+ });
204
+ export {
205
+ GET,
206
+ POST
207
+ };