nextly 0.0.1 → 0.0.2-alpha.0

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,102 @@
1
+ // src/utils/get-trusted-client-ip.ts
2
+ var IPV4_RE = /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/;
3
+ var IPV6_CHAR_RE = /^[0-9a-fA-F:.]+$/;
4
+ function classifyIp(addr) {
5
+ if (IPV4_RE.test(addr)) return 4;
6
+ if (addr.includes(":") && IPV6_CHAR_RE.test(addr) && addr.length <= 45) {
7
+ return 6;
8
+ }
9
+ return 0;
10
+ }
11
+ function getTrustedClientIp(request, options) {
12
+ if (!options.trustProxy) {
13
+ return null;
14
+ }
15
+ const trustedCidrs = (options.trustedProxyIps ?? []).map(parseCidr).filter((c) => c !== null);
16
+ const xff = request.headers.get("x-forwarded-for");
17
+ if (xff) {
18
+ const hops = xff.split(",").map((h) => h.trim()).filter(Boolean);
19
+ for (let i = hops.length - 1; i >= 0; i--) {
20
+ const hop = stripIpv6Brackets(hops[i]);
21
+ if (!classifyIp(hop)) continue;
22
+ if (!isIpInAnyCidr(hop, trustedCidrs)) {
23
+ return hop;
24
+ }
25
+ }
26
+ return null;
27
+ }
28
+ const cfIp = request.headers.get("cf-connecting-ip")?.trim();
29
+ if (cfIp && classifyIp(cfIp)) {
30
+ return cfIp;
31
+ }
32
+ const realIp = request.headers.get("x-real-ip")?.trim();
33
+ if (realIp && classifyIp(realIp)) {
34
+ return realIp;
35
+ }
36
+ return null;
37
+ }
38
+ function parseTrustedProxyIpsEnv(raw) {
39
+ if (!raw) return [];
40
+ return raw.split(",").map((s) => s.trim()).filter(Boolean);
41
+ }
42
+ function stripIpv6Brackets(ip) {
43
+ return ip.startsWith("[") && ip.endsWith("]") ? ip.slice(1, -1) : ip;
44
+ }
45
+ function parseCidr(entry) {
46
+ const [addr, prefixRaw] = entry.split("/");
47
+ const stripped = stripIpv6Brackets(addr);
48
+ const family = classifyIp(stripped);
49
+ if (family === 4) {
50
+ const prefix = prefixRaw === void 0 ? 32 : Number(prefixRaw);
51
+ if (!Number.isInteger(prefix) || prefix < 0 || prefix > 32) return null;
52
+ const intAddr = ipv4ToInt(stripped);
53
+ if (intAddr === null) return null;
54
+ const mask = prefix === 0 ? 0 : -1 >>> 32 - prefix << 32 - prefix;
55
+ return { family: "ipv4", network: intAddr & mask, prefix };
56
+ }
57
+ if (family === 6) {
58
+ if (prefixRaw !== void 0 && prefixRaw !== "128") return null;
59
+ return { family: "ipv6", network: stripped.toLowerCase(), prefix: 128 };
60
+ }
61
+ return null;
62
+ }
63
+ function ipv4ToInt(ip) {
64
+ const parts = ip.split(".");
65
+ if (parts.length !== 4) return null;
66
+ let acc = 0;
67
+ for (const p of parts) {
68
+ const n = Number(p);
69
+ if (!Number.isInteger(n) || n < 0 || n > 255) return null;
70
+ acc = acc << 8 | n;
71
+ }
72
+ return acc >>> 0;
73
+ }
74
+ function isIpInAnyCidr(ip, cidrs) {
75
+ if (cidrs.length === 0) return false;
76
+ const family = classifyIp(ip);
77
+ if (family === 4) {
78
+ const intIp = ipv4ToInt(ip);
79
+ if (intIp === null) return false;
80
+ for (const c of cidrs) {
81
+ if (c.family !== "ipv4") continue;
82
+ const mask = c.prefix === 0 ? 0 : -1 >>> 32 - c.prefix << 32 - c.prefix;
83
+ if ((intIp & mask) >>> 0 === (c.network & mask) >>> 0) {
84
+ return true;
85
+ }
86
+ }
87
+ return false;
88
+ }
89
+ if (family === 6) {
90
+ const lower = ip.toLowerCase();
91
+ for (const c of cidrs) {
92
+ if (c.family === "ipv6" && c.network === lower) return true;
93
+ }
94
+ return false;
95
+ }
96
+ return false;
97
+ }
98
+
99
+ export {
100
+ getTrustedClientIp,
101
+ parseTrustedProxyIpsEnv
102
+ };
@@ -0,0 +1,73 @@
1
+ import {
2
+ seedPermissions
3
+ } from "./chunk-UOP63Q54.mjs";
4
+ import {
5
+ seedSuperAdmin
6
+ } from "./chunk-PKMABBB5.mjs";
7
+
8
+ // src/database/seeders/index.ts
9
+ async function seedAll(adapter, options) {
10
+ const {
11
+ silent = false,
12
+ superAdminEmail,
13
+ superAdminPassword,
14
+ superAdminName,
15
+ skipSuperAdmin = false
16
+ } = options || {};
17
+ const log = silent ? () => {
18
+ } : console.log;
19
+ const errorLog = silent ? () => {
20
+ } : console.error;
21
+ log("\nRunning system bootstrap seeders...\n");
22
+ let totalCreated = 0;
23
+ let totalSkipped = 0;
24
+ let totalErrors = 0;
25
+ const allErrorMessages = [];
26
+ const permissionsResult = await seedPermissions(adapter, { silent });
27
+ totalCreated += permissionsResult.created;
28
+ totalSkipped += permissionsResult.skipped;
29
+ totalErrors += permissionsResult.errors;
30
+ if (permissionsResult.errorMessages) {
31
+ allErrorMessages.push(...permissionsResult.errorMessages);
32
+ }
33
+ if (!skipSuperAdmin) {
34
+ if (permissionsResult.success) {
35
+ const superAdminResult = await seedSuperAdmin(adapter, {
36
+ email: superAdminEmail,
37
+ password: superAdminPassword,
38
+ name: superAdminName,
39
+ silent
40
+ });
41
+ totalCreated += superAdminResult.created;
42
+ totalSkipped += superAdminResult.skipped;
43
+ totalErrors += superAdminResult.errors;
44
+ if (superAdminResult.errorMessages) {
45
+ allErrorMessages.push(...superAdminResult.errorMessages);
46
+ }
47
+ } else {
48
+ errorLog(
49
+ "\nSkipping super admin seeding due to permission seeding failures.\n"
50
+ );
51
+ }
52
+ } else {
53
+ log("\nSuper admin seeding skipped (skipSuperAdmin: true)\n");
54
+ }
55
+ const combinedResult = {
56
+ success: totalErrors === 0,
57
+ created: totalCreated,
58
+ skipped: totalSkipped,
59
+ errors: totalErrors,
60
+ total: totalCreated + totalSkipped + totalErrors,
61
+ errorMessages: allErrorMessages.length > 0 ? allErrorMessages : void 0
62
+ };
63
+ if (combinedResult.success) {
64
+ log("\nSystem bootstrap seeders completed.\n");
65
+ } else {
66
+ errorLog("\nSome seeders failed. Please check the errors above.\n");
67
+ }
68
+ return combinedResult;
69
+ }
70
+
71
+ export {
72
+ seedAll
73
+ };
@@ -0,0 +1,74 @@
1
+ // src/di/container.ts
2
+ var Container = class _Container {
3
+ singletons = /* @__PURE__ */ new Map();
4
+ factories = /* @__PURE__ */ new Map();
5
+ parent;
6
+ constructor(parent) {
7
+ this.parent = parent;
8
+ }
9
+ /**
10
+ * Register a factory that creates a new instance each time get() is called.
11
+ */
12
+ register(name, factory) {
13
+ this.factories.set(name, factory);
14
+ return this;
15
+ }
16
+ /**
17
+ * Register a factory that creates a singleton instance (lazily initialized).
18
+ */
19
+ registerSingleton(name, factory) {
20
+ this.factories.set(name, () => {
21
+ if (!this.singletons.has(name)) {
22
+ this.singletons.set(name, factory());
23
+ }
24
+ return this.singletons.get(name);
25
+ });
26
+ return this;
27
+ }
28
+ /**
29
+ * Get a service by name. Throws if not registered.
30
+ */
31
+ get(name) {
32
+ const factory = this.factories.get(name);
33
+ if (factory) {
34
+ return factory();
35
+ }
36
+ if (this.parent) {
37
+ return this.parent.get(name);
38
+ }
39
+ if (process.env.NODE_ENV === "development") {
40
+ const registered = Array.from(this.factories.keys());
41
+ const registeredList = registered.length > 0 ? registered.join(", ") : "(none)";
42
+ throw new Error(
43
+ `Service "${name}" is not registered in container. Registered services: ${registeredList}`
44
+ );
45
+ }
46
+ throw new Error(`Service "${name}" is not registered in container`);
47
+ }
48
+ /**
49
+ * Check if a service is registered.
50
+ */
51
+ has(name) {
52
+ return this.factories.has(name) || (this.parent?.has(name) ?? false);
53
+ }
54
+ /**
55
+ * Create a child scope container for request-scoped services.
56
+ */
57
+ createScope() {
58
+ return new _Container(this);
59
+ }
60
+ /**
61
+ * Clear all registrations and singletons (useful for testing).
62
+ */
63
+ clear() {
64
+ this.singletons.clear();
65
+ this.factories.clear();
66
+ }
67
+ };
68
+ var globalForNextly = globalThis;
69
+ var container = globalForNextly.__nextly_container ??= new Container();
70
+
71
+ export {
72
+ Container,
73
+ container
74
+ };
@@ -0,0 +1,204 @@
1
+ // src/domains/schema/services/field-column-descriptor.ts
2
+ var LAYOUT_FIELD_TYPES = /* @__PURE__ */ new Set(["tabs", "collapsible", "row"]);
3
+ function toSnakeCase(name) {
4
+ return name.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
5
+ }
6
+ function getColumnDescriptor(field, dialect) {
7
+ if (LAYOUT_FIELD_TYPES.has(field.type)) return null;
8
+ const name = toSnakeCase(field.name);
9
+ const kind = classifyFieldKind(field);
10
+ const nullable = kind === "fkSingle" ? true : field.required !== true;
11
+ if (kind === "skip") return null;
12
+ const dialectType = renderDialectType(
13
+ kind,
14
+ dialect,
15
+ /* length */
16
+ void 0
17
+ );
18
+ const length = lengthForKind(kind);
19
+ return {
20
+ name,
21
+ dialectType,
22
+ ...length !== void 0 ? { length } : {},
23
+ nullable,
24
+ kind
25
+ };
26
+ }
27
+ function classifyFieldKind(field) {
28
+ switch (field.type) {
29
+ case "text":
30
+ case "email":
31
+ case "password":
32
+ case "slug":
33
+ case "select":
34
+ case "radio":
35
+ return "text";
36
+ case "textarea":
37
+ case "richText":
38
+ case "code":
39
+ return "longText";
40
+ case "number": {
41
+ const fmt = field.options?.format;
42
+ return fmt === "float" ? "double" : "integer";
43
+ }
44
+ case "checkbox":
45
+ return "boolean";
46
+ case "date":
47
+ return "timestamp";
48
+ case "relationship":
49
+ case "upload": {
50
+ const hasMany = field.hasMany;
51
+ const relationTo = field.relationTo;
52
+ if (hasMany || Array.isArray(relationTo)) return "json";
53
+ return "fkSingle";
54
+ }
55
+ case "repeater":
56
+ case "group":
57
+ case "blocks":
58
+ case "component":
59
+ case "json":
60
+ case "chips":
61
+ return "json";
62
+ case "point":
63
+ return "json";
64
+ default:
65
+ return "text";
66
+ }
67
+ }
68
+ function renderDialectType(kind, dialect, length) {
69
+ if (kind === "text") {
70
+ if (dialect === "postgresql") return "text";
71
+ if (dialect === "mysql") return `varchar(${length ?? 255})`;
72
+ return "text";
73
+ }
74
+ if (kind === "longText") {
75
+ if (dialect === "postgresql") return "text";
76
+ if (dialect === "mysql") return "text";
77
+ return "text";
78
+ }
79
+ if (kind === "varchar") {
80
+ if (dialect === "postgresql") return "text";
81
+ if (dialect === "mysql") return `varchar(${length ?? 255})`;
82
+ return "text";
83
+ }
84
+ if (kind === "boolean") {
85
+ if (dialect === "postgresql") return "bool";
86
+ if (dialect === "mysql") return "tinyint(1)";
87
+ return "integer";
88
+ }
89
+ if (kind === "integer") {
90
+ if (dialect === "postgresql") return "int4";
91
+ if (dialect === "mysql") return "int";
92
+ return "integer";
93
+ }
94
+ if (kind === "double") {
95
+ if (dialect === "postgresql") return "float8";
96
+ if (dialect === "mysql") return "double";
97
+ return "real";
98
+ }
99
+ if (kind === "timestamp") {
100
+ if (dialect === "postgresql") return "timestamp";
101
+ if (dialect === "mysql") return "timestamp";
102
+ return "integer";
103
+ }
104
+ if (kind === "json") {
105
+ if (dialect === "postgresql") return "jsonb";
106
+ if (dialect === "mysql") return "json";
107
+ return "text";
108
+ }
109
+ if (kind === "fkSingle") {
110
+ if (dialect === "postgresql") return "text";
111
+ if (dialect === "mysql") return "varchar(36)";
112
+ return "text";
113
+ }
114
+ return "text";
115
+ }
116
+ function lengthForKind(kind) {
117
+ if (kind === "text") return 255;
118
+ if (kind === "varchar") return 255;
119
+ if (kind === "fkSingle") return 36;
120
+ return void 0;
121
+ }
122
+ function getSystemColumnDescriptors(dialect, opts) {
123
+ const cols = [];
124
+ if (dialect === "postgresql") {
125
+ cols.push({ name: "id", dialectType: "text", nullable: false, primaryKey: true });
126
+ if (!opts.hasTitleField) {
127
+ cols.push({ name: "title", dialectType: "text", nullable: false, primaryKey: false });
128
+ }
129
+ if (!opts.hasSlugField) {
130
+ cols.push({ name: "slug", dialectType: "text", nullable: false, primaryKey: false });
131
+ }
132
+ cols.push({ name: "created_at", dialectType: "timestamp", nullable: true, primaryKey: false });
133
+ cols.push({ name: "updated_at", dialectType: "timestamp", nullable: true, primaryKey: false });
134
+ if (opts.hasStatus) {
135
+ cols.push({ name: "status", dialectType: "text", nullable: false, primaryKey: false });
136
+ }
137
+ } else if (dialect === "mysql") {
138
+ cols.push({
139
+ name: "id",
140
+ dialectType: "varchar(36)",
141
+ length: 36,
142
+ nullable: false,
143
+ primaryKey: true
144
+ });
145
+ if (!opts.hasTitleField) {
146
+ cols.push({
147
+ name: "title",
148
+ dialectType: "varchar(255)",
149
+ length: 255,
150
+ nullable: false,
151
+ primaryKey: false
152
+ });
153
+ }
154
+ if (!opts.hasSlugField) {
155
+ cols.push({
156
+ name: "slug",
157
+ dialectType: "varchar(255)",
158
+ length: 255,
159
+ nullable: false,
160
+ primaryKey: false
161
+ });
162
+ }
163
+ cols.push({
164
+ name: "created_at",
165
+ dialectType: "timestamp",
166
+ nullable: true,
167
+ primaryKey: false
168
+ });
169
+ cols.push({
170
+ name: "updated_at",
171
+ dialectType: "timestamp",
172
+ nullable: true,
173
+ primaryKey: false
174
+ });
175
+ if (opts.hasStatus) {
176
+ cols.push({
177
+ name: "status",
178
+ dialectType: "varchar(20)",
179
+ length: 20,
180
+ nullable: false,
181
+ primaryKey: false
182
+ });
183
+ }
184
+ } else {
185
+ cols.push({ name: "id", dialectType: "text", nullable: false, primaryKey: true });
186
+ if (!opts.hasTitleField) {
187
+ cols.push({ name: "title", dialectType: "text", nullable: false, primaryKey: false });
188
+ }
189
+ if (!opts.hasSlugField) {
190
+ cols.push({ name: "slug", dialectType: "text", nullable: false, primaryKey: false });
191
+ }
192
+ cols.push({ name: "created_at", dialectType: "integer", nullable: true, primaryKey: false });
193
+ cols.push({ name: "updated_at", dialectType: "integer", nullable: true, primaryKey: false });
194
+ if (opts.hasStatus) {
195
+ cols.push({ name: "status", dialectType: "text", nullable: false, primaryKey: false });
196
+ }
197
+ }
198
+ return cols;
199
+ }
200
+
201
+ export {
202
+ getColumnDescriptor,
203
+ getSystemColumnDescriptors
204
+ };
@@ -0,0 +1,135 @@
1
+ import {
2
+ env
3
+ } from "./chunk-UJ2IMJ4W.mjs";
4
+
5
+ // src/database/factory.ts
6
+ async function createAdapter(config) {
7
+ const type = config?.type ?? detectAdapterType();
8
+ const url = config?.url ?? env.DATABASE_URL;
9
+ if (!url && type !== "sqlite") {
10
+ throw new Error(
11
+ "DATABASE_URL environment variable is required for PostgreSQL and MySQL"
12
+ );
13
+ }
14
+ const adapterConfig = { ...config, url };
15
+ if (type !== "postgresql" && type !== "mysql" && type !== "sqlite") {
16
+ const unknownType = String(type);
17
+ throw new Error(`Unsupported database type: ${unknownType}`);
18
+ }
19
+ const pkgName = type === "postgresql" ? "@nextlyhq/adapter-postgres" : type === "mysql" ? "@nextlyhq/adapter-mysql" : "@nextlyhq/adapter-sqlite";
20
+ let adapter;
21
+ try {
22
+ if (type === "postgresql") {
23
+ const mod = await import("@nextlyhq/adapter-postgres");
24
+ adapter = mod.createPostgresAdapter(adapterConfig);
25
+ } else if (type === "mysql") {
26
+ const mod = await import("@nextlyhq/adapter-mysql");
27
+ adapter = mod.createMySqlAdapter(adapterConfig);
28
+ } else {
29
+ const mod = await import("@nextlyhq/adapter-sqlite");
30
+ const sqliteConfig = {
31
+ ...adapterConfig,
32
+ url: url ?? "file:./data/nextly.db"
33
+ };
34
+ adapter = mod.createSqliteAdapter(sqliteConfig);
35
+ }
36
+ } catch (error) {
37
+ throw new Error(
38
+ `Failed to load database adapter for "${type}". Make sure ${pkgName} is installed:
39
+
40
+ npm install ${pkgName}
41
+
42
+ Original error: ${error instanceof Error ? error.message : String(error)}`
43
+ );
44
+ }
45
+ await adapter.connect();
46
+ return adapter;
47
+ }
48
+ async function createAdapterFromEnv() {
49
+ return createAdapter();
50
+ }
51
+ function detectAdapterType() {
52
+ const dialect = env.DB_DIALECT;
53
+ if (dialect) {
54
+ switch (dialect) {
55
+ case "postgresql":
56
+ return "postgresql";
57
+ case "mysql":
58
+ return "mysql";
59
+ case "sqlite":
60
+ return "sqlite";
61
+ default:
62
+ throw new Error(
63
+ `Unknown DB_DIALECT: ${String(dialect)}. Must be "postgresql", "mysql", or "sqlite"`
64
+ );
65
+ }
66
+ }
67
+ const url = env.DATABASE_URL;
68
+ if (url) {
69
+ if (url.startsWith("postgres://") || url.startsWith("postgresql://")) {
70
+ return "postgresql";
71
+ }
72
+ if (url.startsWith("mysql://")) {
73
+ return "mysql";
74
+ }
75
+ if (url.startsWith("file:") || url.endsWith(".db") || url.endsWith(".sqlite")) {
76
+ return "sqlite";
77
+ }
78
+ }
79
+ console.warn(
80
+ "\u26A0\uFE0F No DB_DIALECT or DATABASE_URL specified, defaulting to PostgreSQL. Set DB_DIALECT environment variable to avoid this warning."
81
+ );
82
+ return "postgresql";
83
+ }
84
+ function validateDatabaseEnv() {
85
+ const errors = [];
86
+ const dialect = env.DB_DIALECT;
87
+ const url = env.DATABASE_URL;
88
+ if (!dialect && !url) {
89
+ errors.push(
90
+ "Either DB_DIALECT or DATABASE_URL must be set. Set DB_DIALECT to 'postgresql', 'mysql', or 'sqlite'."
91
+ );
92
+ }
93
+ if (dialect && !["postgresql", "mysql", "sqlite"].includes(dialect)) {
94
+ errors.push(
95
+ `Invalid DB_DIALECT: "${dialect}". Must be "postgresql", "mysql", or "sqlite".`
96
+ );
97
+ }
98
+ if (dialect && dialect !== "sqlite" && !url) {
99
+ errors.push(
100
+ `DATABASE_URL is required for ${dialect}. Please set DATABASE_URL environment variable with your connection string.`
101
+ );
102
+ }
103
+ return { valid: errors.length === 0, errors };
104
+ }
105
+ async function checkAdapterHealth(adapter) {
106
+ try {
107
+ const connected = adapter.isConnected();
108
+ if (!connected) {
109
+ await adapter.connect();
110
+ }
111
+ const capabilities = adapter.getCapabilities();
112
+ await adapter.executeQuery("SELECT 1 as test");
113
+ const poolStats = adapter.getPoolStats();
114
+ return {
115
+ healthy: true,
116
+ dialect: capabilities.dialect,
117
+ connected: adapter.isConnected(),
118
+ poolStats
119
+ };
120
+ } catch (error) {
121
+ return {
122
+ healthy: false,
123
+ dialect: adapter.getCapabilities().dialect,
124
+ connected: adapter.isConnected(),
125
+ error: error instanceof Error ? error.message : String(error)
126
+ };
127
+ }
128
+ }
129
+
130
+ export {
131
+ createAdapter,
132
+ createAdapterFromEnv,
133
+ validateDatabaseEnv,
134
+ checkAdapterHealth
135
+ };
File without changes
@@ -0,0 +1,57 @@
1
+ // src/auth/middleware/rate-limiter.ts
2
+ var RateLimiter = class {
3
+ /**
4
+ * Internal store: keyId → sorted array of allowed request timestamps (ms).
5
+ * Arrays are bounded at `limit` entries per key.
6
+ */
7
+ windows = /* @__PURE__ */ new Map();
8
+ /**
9
+ * Check whether a request for `keyId` is allowed under the given rate limit.
10
+ *
11
+ * @param keyId - The API key ID (used as the map key — NOT the raw key string).
12
+ * @param limit - Maximum number of requests allowed within `windowMs`.
13
+ * @param windowMs - Sliding window size in milliseconds (e.g. 3_600_000 for 1 hour).
14
+ * @returns `{ allowed, remaining, resetAt }`
15
+ */
16
+ check(keyId, limit, windowMs) {
17
+ const now = Date.now();
18
+ const windowStart = now - windowMs;
19
+ let timestamps = this.windows.get(keyId) ?? [];
20
+ timestamps = timestamps.filter((t) => t > windowStart);
21
+ const count = timestamps.length;
22
+ const allowed = count < limit;
23
+ if (allowed) {
24
+ timestamps.push(now);
25
+ this.windows.set(keyId, timestamps);
26
+ }
27
+ const remaining = Math.max(0, limit - timestamps.length);
28
+ const oldestInWindow = timestamps[0];
29
+ const resetAt = new Date(
30
+ oldestInWindow !== void 0 ? oldestInWindow + windowMs : now + windowMs
31
+ );
32
+ return { allowed, remaining, resetAt };
33
+ }
34
+ /**
35
+ * Remove all state for a given key.
36
+ *
37
+ * Useful for tests or if a key is revoked and its slot should be freed
38
+ * immediately rather than waiting for natural expiry.
39
+ *
40
+ * @param keyId - The API key ID whose window should be cleared.
41
+ */
42
+ clear(keyId) {
43
+ this.windows.delete(keyId);
44
+ }
45
+ /**
46
+ * Return the number of keys currently tracked.
47
+ * Intended for testing and monitoring only.
48
+ */
49
+ get size() {
50
+ return this.windows.size;
51
+ }
52
+ };
53
+ var rateLimiter = new RateLimiter();
54
+
55
+ export {
56
+ rateLimiter
57
+ };