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,488 @@
1
+ import {
2
+ MAX_COMPONENT_NESTING_DEPTH,
3
+ SQL_RESERVED_KEYWORDS
4
+ } from "./chunk-FQULBZ53.mjs";
5
+
6
+ // src/shared/types/config.ts
7
+ var DEFAULT_AUTH_CONFIG = {
8
+ revealRegistrationConflict: false
9
+ };
10
+ var DEFAULT_TYPESCRIPT_CONFIG = {
11
+ outputFile: "./src/types/generated/payload-types.ts",
12
+ declare: true
13
+ };
14
+ var DEFAULT_DB_CONFIG = {
15
+ schemasDir: "./src/db/schemas/collections",
16
+ migrationsDir: "./src/db/migrations"
17
+ };
18
+ var DEFAULT_RATE_LIMIT_CONFIG = {
19
+ readLimit: 100,
20
+ writeLimit: 30,
21
+ windowMs: 6e4
22
+ };
23
+ var DEFAULT_API_KEYS_CONFIG = {
24
+ requestsPerHour: 1e3,
25
+ windowMs: 36e5
26
+ };
27
+ function sanitizeConfig(config) {
28
+ if (config.apiKeys?.rateLimit?.requestsPerHour !== void 0) {
29
+ if (!Number.isInteger(config.apiKeys.rateLimit.requestsPerHour) || config.apiKeys.rateLimit.requestsPerHour <= 0) {
30
+ throw new Error(
31
+ `apiKeys.rateLimit.requestsPerHour must be a positive integer (got ${config.apiKeys.rateLimit.requestsPerHour})`
32
+ );
33
+ }
34
+ }
35
+ if (config.apiKeys?.rateLimit?.windowMs !== void 0) {
36
+ if (typeof config.apiKeys.rateLimit.windowMs !== "number" || config.apiKeys.rateLimit.windowMs <= 0) {
37
+ throw new Error(
38
+ `apiKeys.rateLimit.windowMs must be a positive number (got ${config.apiKeys.rateLimit.windowMs})`
39
+ );
40
+ }
41
+ }
42
+ let rateLimit;
43
+ if (config.rateLimit?.enabled !== false) {
44
+ rateLimit = {
45
+ enabled: true,
46
+ readLimit: config.rateLimit?.readLimit ?? DEFAULT_RATE_LIMIT_CONFIG.readLimit,
47
+ writeLimit: config.rateLimit?.writeLimit ?? DEFAULT_RATE_LIMIT_CONFIG.writeLimit,
48
+ windowMs: config.rateLimit?.windowMs ?? DEFAULT_RATE_LIMIT_CONFIG.windowMs,
49
+ store: config.rateLimit?.store,
50
+ keyGenerator: config.rateLimit?.keyGenerator,
51
+ skip: config.rateLimit?.skip,
52
+ collections: config.rateLimit?.collections
53
+ };
54
+ }
55
+ const apiKeys = config.apiKeys ? {
56
+ rateLimit: {
57
+ requestsPerHour: config.apiKeys.rateLimit?.requestsPerHour ?? DEFAULT_API_KEYS_CONFIG.requestsPerHour,
58
+ windowMs: config.apiKeys.rateLimit?.windowMs ?? DEFAULT_API_KEYS_CONFIG.windowMs
59
+ }
60
+ } : void 0;
61
+ return {
62
+ collections: config.collections ?? [],
63
+ singles: config.singles ?? [],
64
+ components: config.components ?? [],
65
+ users: config.users,
66
+ email: config.email,
67
+ typescript: {
68
+ outputFile: config.typescript?.outputFile ?? DEFAULT_TYPESCRIPT_CONFIG.outputFile,
69
+ declare: config.typescript?.declare ?? DEFAULT_TYPESCRIPT_CONFIG.declare
70
+ },
71
+ db: {
72
+ schemasDir: config.db?.schemasDir ?? DEFAULT_DB_CONFIG.schemasDir,
73
+ migrationsDir: config.db?.migrationsDir ?? DEFAULT_DB_CONFIG.migrationsDir
74
+ },
75
+ rateLimit,
76
+ apiKeys,
77
+ // PR 5 (unified-error-system): always present after sanitization so
78
+ // downstream code can read `config.auth.revealRegistrationConflict`
79
+ // without nil checks. Defaults to silent-success per spec §13.2.
80
+ auth: {
81
+ revealRegistrationConflict: config.auth?.revealRegistrationConflict ?? DEFAULT_AUTH_CONFIG.revealRegistrationConflict
82
+ },
83
+ storage: config.storage ?? [],
84
+ plugins: config.plugins ?? [],
85
+ security: config.security,
86
+ admin: config.admin
87
+ };
88
+ }
89
+
90
+ // src/users/config/validate-user-config.ts
91
+ var RESERVED_USER_FIELD_NAMES = [
92
+ "id",
93
+ "name",
94
+ "email",
95
+ "emailVerified",
96
+ "passwordHash",
97
+ "passwordUpdatedAt",
98
+ "image",
99
+ "isActive",
100
+ "createdAt",
101
+ "updatedAt",
102
+ "roles",
103
+ "accounts",
104
+ "password"
105
+ ];
106
+ var ALLOWED_USER_FIELD_TYPES = [
107
+ "text",
108
+ "textarea",
109
+ "number",
110
+ "email",
111
+ "select",
112
+ "radio",
113
+ "checkbox",
114
+ "date"
115
+ ];
116
+ var RESERVED_NAMES_SET = new Set(
117
+ RESERVED_USER_FIELD_NAMES.map((n) => n.toLowerCase())
118
+ );
119
+ var ALLOWED_TYPES_SET = new Set(ALLOWED_USER_FIELD_TYPES);
120
+ var SQL_KEYWORDS_SET = new Set(SQL_RESERVED_KEYWORDS);
121
+ var FIELD_NAME_PATTERN = /^[a-zA-Z][a-zA-Z0-9_]*$/;
122
+ function isSQLKeyword(name) {
123
+ return SQL_KEYWORDS_SET.has(name.toLowerCase());
124
+ }
125
+ function isReservedUserFieldName(name) {
126
+ return RESERVED_NAMES_SET.has(name.toLowerCase());
127
+ }
128
+ function validateUserFieldName(name, path, errors, seenNames) {
129
+ if (!name) {
130
+ errors.push({
131
+ path: `${path}.name`,
132
+ message: "Field name is required",
133
+ code: "USER_FIELD_NAME_REQUIRED"
134
+ });
135
+ return;
136
+ }
137
+ if (typeof name !== "string") {
138
+ errors.push({
139
+ path: `${path}.name`,
140
+ message: "Field name must be a string",
141
+ code: "USER_FIELD_NAME_REQUIRED"
142
+ });
143
+ return;
144
+ }
145
+ if (!FIELD_NAME_PATTERN.test(name)) {
146
+ errors.push({
147
+ path: `${path}.name`,
148
+ message: `Field name '${name}' must start with a letter and contain only letters, numbers, and underscores`,
149
+ code: "USER_FIELD_NAME_INVALID_FORMAT"
150
+ });
151
+ }
152
+ if (isReservedUserFieldName(name)) {
153
+ errors.push({
154
+ path: `${path}.name`,
155
+ message: `Field name '${name}' conflicts with a built-in user field. Reserved names: ${RESERVED_USER_FIELD_NAMES.join(", ")}`,
156
+ code: "USER_FIELD_NAME_RESERVED"
157
+ });
158
+ }
159
+ if (isSQLKeyword(name)) {
160
+ errors.push({
161
+ path: `${path}.name`,
162
+ message: `Field name '${name}' is a SQL reserved keyword. Consider using a different name like '${name}Field' or '${name}Value'`,
163
+ code: "USER_FIELD_NAME_SQL_KEYWORD"
164
+ });
165
+ }
166
+ const nameLower = name.toLowerCase();
167
+ if (seenNames.has(nameLower)) {
168
+ errors.push({
169
+ path: `${path}.name`,
170
+ message: `Duplicate field name '${name}'`,
171
+ code: "USER_FIELD_NAME_DUPLICATE"
172
+ });
173
+ } else {
174
+ seenNames.add(nameLower);
175
+ }
176
+ }
177
+ function validateUserFieldType(field, path, errors) {
178
+ const fieldType = field.type;
179
+ if (!fieldType) {
180
+ errors.push({
181
+ path: `${path}.type`,
182
+ message: "Field type is required",
183
+ code: "USER_FIELD_TYPE_REQUIRED"
184
+ });
185
+ return;
186
+ }
187
+ if (typeof fieldType !== "string" || !ALLOWED_TYPES_SET.has(fieldType)) {
188
+ errors.push({
189
+ path: `${path}.type`,
190
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
191
+ message: `User custom fields do not support type '${String(fieldType)}'. Allowed types: ${ALLOWED_USER_FIELD_TYPES.join(", ")}`,
192
+ code: "USER_FIELD_TYPE_NOT_ALLOWED"
193
+ });
194
+ }
195
+ }
196
+ function validateUserSelectOptions(field, path, errors, fieldType) {
197
+ const options = field.options;
198
+ if (!options) {
199
+ errors.push({
200
+ path: `${path}.options`,
201
+ message: `${fieldType} field must have an 'options' array`,
202
+ code: fieldType === "select" ? "USER_SELECT_OPTIONS_REQUIRED" : "USER_RADIO_OPTIONS_REQUIRED"
203
+ });
204
+ return;
205
+ }
206
+ if (!Array.isArray(options)) {
207
+ errors.push({
208
+ path: `${path}.options`,
209
+ message: `${fieldType} field 'options' must be an array`,
210
+ code: fieldType === "select" ? "USER_SELECT_OPTIONS_REQUIRED" : "USER_RADIO_OPTIONS_REQUIRED"
211
+ });
212
+ return;
213
+ }
214
+ if (options.length === 0) {
215
+ errors.push({
216
+ path: `${path}.options`,
217
+ message: `${fieldType} field must have at least one option`,
218
+ code: fieldType === "select" ? "USER_SELECT_OPTIONS_EMPTY" : "USER_RADIO_OPTIONS_EMPTY"
219
+ });
220
+ }
221
+ }
222
+ function validateUserFields(fields, errors) {
223
+ const fieldNames = /* @__PURE__ */ new Set();
224
+ if (fields === void 0 || fields === null) {
225
+ return fieldNames;
226
+ }
227
+ if (!Array.isArray(fields)) {
228
+ errors.push({
229
+ path: "fields",
230
+ message: "User fields must be an array",
231
+ code: "USER_FIELDS_INVALID_TYPE"
232
+ });
233
+ return fieldNames;
234
+ }
235
+ const seenNames = /* @__PURE__ */ new Set();
236
+ fields.forEach((field, index) => {
237
+ const fieldPath = `fields[${index}]`;
238
+ if (!field || typeof field !== "object") {
239
+ return;
240
+ }
241
+ const f = field;
242
+ validateUserFieldType(f, fieldPath, errors);
243
+ validateUserFieldName(f.name, fieldPath, errors, seenNames);
244
+ const fieldType = f.type;
245
+ if (fieldType === "select") {
246
+ validateUserSelectOptions(f, fieldPath, errors, "select");
247
+ } else if (fieldType === "radio") {
248
+ validateUserSelectOptions(f, fieldPath, errors, "radio");
249
+ }
250
+ if (typeof f.name === "string" && FIELD_NAME_PATTERN.test(f.name)) {
251
+ fieldNames.add(f.name);
252
+ }
253
+ });
254
+ return fieldNames;
255
+ }
256
+ function validateAdminOptions(admin, fieldNames, errors) {
257
+ if (admin === void 0 || admin === null) {
258
+ return;
259
+ }
260
+ if (typeof admin !== "object" || Array.isArray(admin)) {
261
+ errors.push({
262
+ path: "admin",
263
+ message: "Admin options must be an object",
264
+ code: "USER_ADMIN_INVALID_TYPE"
265
+ });
266
+ return;
267
+ }
268
+ const adminObj = admin;
269
+ if (adminObj.listFields !== void 0) {
270
+ if (!Array.isArray(adminObj.listFields)) {
271
+ errors.push({
272
+ path: "admin.listFields",
273
+ message: "admin.listFields must be an array of field names",
274
+ code: "USER_ADMIN_INVALID_TYPE"
275
+ });
276
+ } else {
277
+ adminObj.listFields.forEach((ref, index) => {
278
+ if (typeof ref !== "string") {
279
+ errors.push({
280
+ path: `admin.listFields[${index}]`,
281
+ message: "Each listFields entry must be a string",
282
+ code: "USER_ADMIN_LIST_FIELD_UNKNOWN"
283
+ });
284
+ } else if (!fieldNames.has(ref)) {
285
+ const available = fieldNames.size > 0 ? `Available fields: ${Array.from(fieldNames).sort().join(", ")}` : "No custom fields defined";
286
+ errors.push({
287
+ path: `admin.listFields[${index}]`,
288
+ message: `Unknown field '${ref}' in admin.listFields. ${available}`,
289
+ code: "USER_ADMIN_LIST_FIELD_UNKNOWN"
290
+ });
291
+ }
292
+ });
293
+ }
294
+ }
295
+ if (adminObj.group !== void 0 && typeof adminObj.group !== "string") {
296
+ errors.push({
297
+ path: "admin.group",
298
+ message: "admin.group must be a string",
299
+ code: "USER_ADMIN_GROUP_INVALID_TYPE"
300
+ });
301
+ }
302
+ }
303
+ function validateUserConfig(config) {
304
+ const errors = [];
305
+ const fieldNames = validateUserFields(config.fields, errors);
306
+ validateAdminOptions(config.admin, fieldNames, errors);
307
+ return {
308
+ valid: errors.length === 0,
309
+ errors
310
+ };
311
+ }
312
+ function assertValidUserConfig(config) {
313
+ const result = validateUserConfig(config);
314
+ if (!result.valid) {
315
+ const errorMessages = result.errors.map((err) => ` - [${err.code}] ${err.path}: ${err.message}`).join("\n");
316
+ throw new Error(`Invalid user config:
317
+ ${errorMessages}`);
318
+ }
319
+ }
320
+
321
+ // src/collections/config/define-config.ts
322
+ function collectComponentRefs(fields, refs) {
323
+ for (const field of fields) {
324
+ if (field.type === "component") {
325
+ if (typeof field.component === "string") {
326
+ refs.push(field.component);
327
+ }
328
+ if (Array.isArray(field.components)) {
329
+ for (const slug of field.components) {
330
+ if (typeof slug === "string") {
331
+ refs.push(slug);
332
+ }
333
+ }
334
+ }
335
+ }
336
+ if (Array.isArray(field.fields)) {
337
+ collectComponentRefs(
338
+ field.fields,
339
+ refs
340
+ );
341
+ }
342
+ }
343
+ }
344
+ function validateComponentNesting(components) {
345
+ const graph = /* @__PURE__ */ new Map();
346
+ const slugSet = /* @__PURE__ */ new Set();
347
+ for (const comp of components) {
348
+ const slug = comp.slug.toLowerCase();
349
+ slugSet.add(slug);
350
+ const refs = [];
351
+ collectComponentRefs(
352
+ comp.fields,
353
+ refs
354
+ );
355
+ graph.set(
356
+ slug,
357
+ refs.filter((r) => slugSet.has(r.toLowerCase())).map((r) => r.toLowerCase())
358
+ );
359
+ }
360
+ for (const [slug, refs] of graph) {
361
+ graph.set(
362
+ slug,
363
+ refs.filter((r) => slugSet.has(r))
364
+ );
365
+ }
366
+ const visited = /* @__PURE__ */ new Set();
367
+ const inStack = /* @__PURE__ */ new Set();
368
+ function detectCycle(slug, path) {
369
+ if (inStack.has(slug)) {
370
+ return [...path, slug];
371
+ }
372
+ if (visited.has(slug)) return null;
373
+ visited.add(slug);
374
+ inStack.add(slug);
375
+ for (const ref of graph.get(slug) ?? []) {
376
+ const cycle = detectCycle(ref, [...path, slug]);
377
+ if (cycle) return cycle;
378
+ }
379
+ inStack.delete(slug);
380
+ return null;
381
+ }
382
+ for (const slug of graph.keys()) {
383
+ if (!visited.has(slug)) {
384
+ const cycle = detectCycle(slug, []);
385
+ if (cycle) {
386
+ const cycleStr = cycle.join(" \u2192 ");
387
+ throw new Error(
388
+ `Circular component reference detected: ${cycleStr}. Components cannot reference each other in a cycle.`
389
+ );
390
+ }
391
+ }
392
+ }
393
+ const depthCache = /* @__PURE__ */ new Map();
394
+ function getMaxDepth(slug) {
395
+ if (depthCache.has(slug)) return depthCache.get(slug);
396
+ const refs = graph.get(slug) ?? [];
397
+ let maxChildDepth = 0;
398
+ for (const ref of refs) {
399
+ maxChildDepth = Math.max(maxChildDepth, getMaxDepth(ref));
400
+ }
401
+ const depth = 1 + maxChildDepth;
402
+ depthCache.set(slug, depth);
403
+ return depth;
404
+ }
405
+ for (const slug of graph.keys()) {
406
+ const depth = getMaxDepth(slug);
407
+ if (depth > MAX_COMPONENT_NESTING_DEPTH) {
408
+ throw new Error(
409
+ `Component nesting depth exceeds maximum of ${MAX_COMPONENT_NESTING_DEPTH} levels (component '${slug}' has a nesting chain ${depth} levels deep). Simplify the component structure to reduce nesting.`
410
+ );
411
+ }
412
+ }
413
+ }
414
+ function validateNextlyConfig(config) {
415
+ const collections = config.collections ?? [];
416
+ const slugs = /* @__PURE__ */ new Set();
417
+ for (const collection of collections) {
418
+ const slug = collection.slug.toLowerCase();
419
+ if (slugs.has(slug)) {
420
+ throw new Error(
421
+ `Duplicate collection slug: '${collection.slug}'. Each collection must have a unique slug.`
422
+ );
423
+ }
424
+ slugs.add(slug);
425
+ }
426
+ const singles = config.singles ?? [];
427
+ for (const single of singles) {
428
+ const slug = single.slug.toLowerCase();
429
+ if (slugs.has(slug)) {
430
+ const isCollectionConflict = collections.some(
431
+ (c) => c.slug.toLowerCase() === slug
432
+ );
433
+ if (isCollectionConflict) {
434
+ throw new Error(
435
+ `Single slug '${single.slug}' conflicts with a Collection slug. Singles and Collections must have unique slugs.`
436
+ );
437
+ } else {
438
+ throw new Error(
439
+ `Duplicate Single slug: '${single.slug}'. Each Single must have a unique slug.`
440
+ );
441
+ }
442
+ }
443
+ slugs.add(slug);
444
+ }
445
+ const components = config.components ?? [];
446
+ for (const comp of components) {
447
+ const slug = comp.slug.toLowerCase();
448
+ if (slugs.has(slug)) {
449
+ const isCollectionConflict = collections.some(
450
+ (c) => c.slug.toLowerCase() === slug
451
+ );
452
+ const isSingleConflict = singles.some((s) => s.slug.toLowerCase() === slug);
453
+ if (isCollectionConflict) {
454
+ throw new Error(
455
+ `Component slug '${comp.slug}' conflicts with a Collection slug. Components, Collections, and Singles must have unique slugs.`
456
+ );
457
+ } else if (isSingleConflict) {
458
+ throw new Error(
459
+ `Component slug '${comp.slug}' conflicts with a Single slug. Components, Collections, and Singles must have unique slugs.`
460
+ );
461
+ } else {
462
+ throw new Error(
463
+ `Duplicate Component slug: '${comp.slug}'. Each Component must have a unique slug.`
464
+ );
465
+ }
466
+ }
467
+ slugs.add(slug);
468
+ }
469
+ if (components.length > 0) {
470
+ validateComponentNesting(components);
471
+ }
472
+ if (config.users) {
473
+ assertValidUserConfig(config.users);
474
+ }
475
+ }
476
+ function defineConfig(config) {
477
+ validateNextlyConfig(config);
478
+ return sanitizeConfig(config);
479
+ }
480
+
481
+ export {
482
+ sanitizeConfig,
483
+ RESERVED_USER_FIELD_NAMES,
484
+ ALLOWED_USER_FIELD_TYPES,
485
+ validateUserConfig,
486
+ assertValidUserConfig,
487
+ defineConfig
488
+ };
@@ -0,0 +1,19 @@
1
+ import {
2
+ NextlyError
3
+ } from "./chunk-NRUWQ5Z7.mjs";
4
+
5
+ // src/api/zod-to-nextly-error.ts
6
+ function nextlyValidationFromZod(err) {
7
+ return NextlyError.validation({
8
+ errors: err.issues.map((issue) => ({
9
+ path: issue.path.join("."),
10
+ code: issue.code,
11
+ message: issue.message
12
+ })),
13
+ logContext: { zodIssues: err.issues }
14
+ });
15
+ }
16
+
17
+ export {
18
+ nextlyValidationFromZod
19
+ };
@@ -0,0 +1,69 @@
1
+ import {
2
+ RealClassifier,
3
+ RegexRenameDetector,
4
+ buildDesiredTableFromComponentFields,
5
+ buildDesiredTableFromFields,
6
+ countNulls,
7
+ countRows,
8
+ diffSnapshots,
9
+ introspectLiveSnapshot
10
+ } from "./chunk-SBACDPNX.mjs";
11
+
12
+ // src/domains/schema/pipeline/preview.ts
13
+ async function previewDesiredSchema(args, deps = {}) {
14
+ const { desired, db, dialect } = args;
15
+ const renameDetector = deps.renameDetector ?? new RegexRenameDetector();
16
+ const classifier = deps.classifier ?? new RealClassifier();
17
+ const introspect = deps.introspect ?? introspectLiveSnapshot;
18
+ const managedTableNames = [
19
+ ...Object.values(desired.collections).map((c) => c.tableName),
20
+ ...Object.values(desired.singles).map((s) => s.tableName),
21
+ ...Object.values(desired.components).map((c) => c.tableName)
22
+ ];
23
+ const liveSnapshot = await introspect(db, dialect, managedTableNames);
24
+ const collectionTables = Object.values(desired.collections).map(
25
+ (c) => buildDesiredTableFromFields(
26
+ c.tableName,
27
+ c.fields,
28
+ dialect
29
+ )
30
+ );
31
+ const singleTables = Object.values(desired.singles).map(
32
+ (s) => buildDesiredTableFromFields(
33
+ s.tableName,
34
+ s.fields,
35
+ dialect
36
+ )
37
+ );
38
+ const componentTables = Object.values(desired.components).map(
39
+ (c) => buildDesiredTableFromComponentFields(
40
+ c.tableName,
41
+ c.fields,
42
+ dialect
43
+ )
44
+ );
45
+ const desiredSnapshot = {
46
+ tables: [...collectionTables, ...singleTables, ...componentTables]
47
+ };
48
+ const operations = diffSnapshots(liveSnapshot, desiredSnapshot);
49
+ const candidates = renameDetector.detect(operations, dialect);
50
+ const classificationResult = await classifier.classify({
51
+ operations,
52
+ drizzleWarnings: [],
53
+ hasDataLoss: false,
54
+ countNulls: (table, column) => countNulls(db, dialect, table, column),
55
+ countRows: (table) => countRows(db, dialect, table),
56
+ dialect
57
+ });
58
+ return {
59
+ operations,
60
+ events: classificationResult.events,
61
+ candidates,
62
+ classification: classificationResult.level,
63
+ liveSnapshot
64
+ };
65
+ }
66
+
67
+ export {
68
+ previewDesiredSchema
69
+ };