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,3166 @@
1
+ import {
2
+ routeAuthRequest
3
+ } from "./chunk-A3WPLSDT.mjs";
4
+ import {
5
+ POST
6
+ } from "./chunk-YV4Y7SDL.mjs";
7
+ import {
8
+ readJsonBody
9
+ } from "./chunk-VQJQHVEV.mjs";
10
+ import {
11
+ POST as POST2
12
+ } from "./chunk-LDKCUMHK.mjs";
13
+ import {
14
+ createJsonErrorResponse,
15
+ isErrorResponse,
16
+ requireAnyPermission,
17
+ requireAuthentication,
18
+ requireCollectionAccess,
19
+ requirePermission,
20
+ toNextlyAuthError
21
+ } from "./chunk-2Q2SX2CS.mjs";
22
+ import {
23
+ nextlyValidationFromZod
24
+ } from "./chunk-GJNSJU4S.mjs";
25
+ import {
26
+ getForegroundForBackground,
27
+ hexToHslTriplet,
28
+ isValidHex
29
+ } from "./chunk-PWS6XGJK.mjs";
30
+ import {
31
+ CreateApiKeySchema,
32
+ UpdateApiKeySchema,
33
+ createCorsMiddleware,
34
+ createSecurityHeadersMiddleware
35
+ } from "./chunk-YZZCTONM.mjs";
36
+ import {
37
+ createRateLimiter
38
+ } from "./chunk-ERCNLX3V.mjs";
39
+ import {
40
+ parseTrustedProxyIpsEnv
41
+ } from "./chunk-APKKRD2G.mjs";
42
+ import {
43
+ withErrorHandler
44
+ } from "./chunk-TO5AFLVQ.mjs";
45
+ import {
46
+ ensureHmrListener,
47
+ getCachedNextly
48
+ } from "./chunk-P7NH2OSC.mjs";
49
+ import {
50
+ getService,
51
+ isServicesRegistered,
52
+ registerServices
53
+ } from "./chunk-X7TXCYYN.mjs";
54
+ import {
55
+ readOrGenerateRequestId
56
+ } from "./chunk-67GXH6PR.mjs";
57
+ import {
58
+ getNextlyLogger
59
+ } from "./chunk-W4MGXIRR.mjs";
60
+ import {
61
+ ImageSizeService,
62
+ ServiceDispatcher,
63
+ parseWhereQuery
64
+ } from "./chunk-NSEFNNU4.mjs";
65
+ import {
66
+ containsSuperAdminRole,
67
+ hasSuperAdminExcluding,
68
+ isSuperAdmin,
69
+ listEffectivePermissions
70
+ } from "./chunk-W5KKPZT5.mjs";
71
+ import {
72
+ BaseService,
73
+ withTimezoneFormatting
74
+ } from "./chunk-2W3DVD7S.mjs";
75
+ import {
76
+ getDialectTables
77
+ } from "./chunk-TS7GHTG2.mjs";
78
+ import {
79
+ nextlyMigrationJournalMysql,
80
+ nextlyMigrationJournalPg,
81
+ nextlyMigrationJournalSqlite
82
+ } from "./chunk-H26B4FYG.mjs";
83
+ import {
84
+ env
85
+ } from "./chunk-UJ2IMJ4W.mjs";
86
+ import {
87
+ getImageProcessor,
88
+ getMediaStorage
89
+ } from "./chunk-EGXBZCGC.mjs";
90
+ import {
91
+ respondAction,
92
+ respondData,
93
+ respondDoc,
94
+ respondList,
95
+ respondMutation
96
+ } from "./chunk-IUDOC7N7.mjs";
97
+ import {
98
+ container
99
+ } from "./chunk-D5HQBNUB.mjs";
100
+ import {
101
+ NextlyError
102
+ } from "./chunk-NRUWQ5Z7.mjs";
103
+
104
+ // src/api/api-keys.ts
105
+ import { z } from "zod";
106
+ async function getApiKeyService() {
107
+ await getCachedNextly();
108
+ return container.get("apiKeyService");
109
+ }
110
+ async function requireApiKeyPermission(req, action) {
111
+ return requireAnyPermission(req, [
112
+ { action, resource: "api-keys" },
113
+ { action: "update", resource: "api-keys" }
114
+ ]);
115
+ }
116
+ function denySessionOnly(action) {
117
+ throw NextlyError.forbidden({
118
+ logContext: { reason: "session-only", action }
119
+ });
120
+ }
121
+ var listApiKeys = withErrorHandler(
122
+ async (req) => {
123
+ const authResult = await requireApiKeyPermission(req, "read");
124
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
125
+ const service = await getApiKeyService();
126
+ const allUsers = await isSuperAdmin(authResult.userId);
127
+ const keys = await service.listApiKeys(authResult.userId, { allUsers });
128
+ return respondList(keys, {
129
+ total: keys.length,
130
+ page: 1,
131
+ limit: keys.length,
132
+ totalPages: 1,
133
+ hasNext: false,
134
+ hasPrev: false
135
+ });
136
+ }
137
+ );
138
+ function getApiKeyById(req, id) {
139
+ return withErrorHandler(async (request) => {
140
+ const authResult = await requireApiKeyPermission(request, "read");
141
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
142
+ const service = await getApiKeyService();
143
+ const allUsers = await isSuperAdmin(authResult.userId);
144
+ const key = await service.getApiKeyById(id, authResult.userId, {
145
+ allUsers
146
+ });
147
+ if (!key) {
148
+ throw NextlyError.notFound({
149
+ logContext: { entity: "api-key", id, callerId: authResult.userId }
150
+ });
151
+ }
152
+ return respondDoc(key);
153
+ })(req);
154
+ }
155
+ var createApiKey = withErrorHandler(
156
+ async (req) => {
157
+ const authResult = await requireApiKeyPermission(req, "create");
158
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
159
+ if (authResult.authMethod !== "session") denySessionOnly("create");
160
+ const body = await readJsonBody(req);
161
+ let validated;
162
+ try {
163
+ validated = CreateApiKeySchema.parse(body);
164
+ } catch (err) {
165
+ if (err instanceof z.ZodError) throw nextlyValidationFromZod(err);
166
+ throw err;
167
+ }
168
+ const service = await getApiKeyService();
169
+ const { meta, key } = await service.createApiKey(
170
+ authResult.userId,
171
+ validated
172
+ );
173
+ return respondMutation(
174
+ "API key created.",
175
+ { doc: meta, key },
176
+ { status: 201 }
177
+ );
178
+ }
179
+ );
180
+ function updateApiKey(req, id) {
181
+ return withErrorHandler(async (request) => {
182
+ const authResult = await requireApiKeyPermission(request, "update");
183
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
184
+ if (authResult.authMethod !== "session") denySessionOnly("update");
185
+ const body = await readJsonBody(request);
186
+ let validated;
187
+ try {
188
+ validated = UpdateApiKeySchema.parse(body);
189
+ } catch (err) {
190
+ if (err instanceof z.ZodError) throw nextlyValidationFromZod(err);
191
+ throw err;
192
+ }
193
+ const service = await getApiKeyService();
194
+ const updated = await service.updateApiKey(
195
+ id,
196
+ authResult.userId,
197
+ validated
198
+ );
199
+ return respondMutation("API key updated.", updated);
200
+ })(req);
201
+ }
202
+ function revokeApiKey(req, id) {
203
+ return withErrorHandler(async (request) => {
204
+ const authResult = await requireApiKeyPermission(request, "delete");
205
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
206
+ if (authResult.authMethod !== "session") denySessionOnly("delete");
207
+ const service = await getApiKeyService();
208
+ await service.revokeApiKey(id, authResult.userId);
209
+ return respondAction("API key revoked.", { id });
210
+ })(req);
211
+ }
212
+
213
+ // src/api/dashboard.ts
214
+ var PRIVATE_NO_STORE_HEADERS = {
215
+ "Cache-Control": "private, no-store",
216
+ Vary: "Cookie"
217
+ };
218
+ async function getDashboardService() {
219
+ await getCachedNextly();
220
+ return container.get("dashboardService");
221
+ }
222
+ async function getActivityLogService() {
223
+ await getCachedNextly();
224
+ return container.get("activityLogService");
225
+ }
226
+ async function resolveReadableResources(userId) {
227
+ if (await isSuperAdmin(userId)) return void 0;
228
+ const permissionPairs = await listEffectivePermissions(userId);
229
+ return new Set(
230
+ permissionPairs.filter((pair) => pair.endsWith(":read")).map((pair) => pair.split(":")[0])
231
+ );
232
+ }
233
+ var getDashboardStats = withErrorHandler(async (req) => {
234
+ const auth = await requireAuthentication(req);
235
+ if (isErrorResponse(auth)) throw toNextlyAuthError(auth);
236
+ const service = await getDashboardService();
237
+ const readableResources = await resolveReadableResources(auth.userId);
238
+ const stats = await service.getStats({ readableResources });
239
+ return respondData({ ...stats }, { headers: PRIVATE_NO_STORE_HEADERS });
240
+ });
241
+ var getDashboardRecentEntries = withErrorHandler(
242
+ async (req) => {
243
+ const auth = await requireAuthentication(req);
244
+ if (isErrorResponse(auth)) throw toNextlyAuthError(auth);
245
+ const { searchParams } = new URL(req.url);
246
+ const limitParam = searchParams.get("limit");
247
+ const limit = limitParam ? Math.min(Math.max(Number(limitParam) || 5, 1), 20) : 5;
248
+ const service = await getDashboardService();
249
+ const readableResources = await resolveReadableResources(auth.userId);
250
+ const entries = await service.getRecentEntries(limit, readableResources);
251
+ return respondData(
252
+ { ...entries },
253
+ {
254
+ headers: PRIVATE_NO_STORE_HEADERS
255
+ }
256
+ );
257
+ }
258
+ );
259
+ var getDashboardActivity = withErrorHandler(async (req) => {
260
+ const auth = await requireAuthentication(req);
261
+ if (isErrorResponse(auth)) throw toNextlyAuthError(auth);
262
+ const { searchParams } = new URL(req.url);
263
+ const limitParam = searchParams.get("limit");
264
+ const limit = limitParam ? Math.min(Math.max(Number(limitParam) || 5, 1), 50) : 5;
265
+ const service = await getActivityLogService();
266
+ const result = await service.getRecentActivity({ limit });
267
+ return respondData({ ...result }, { headers: PRIVATE_NO_STORE_HEADERS });
268
+ });
269
+
270
+ // src/api/general-settings.ts
271
+ import { z as z2 } from "zod";
272
+ async function getGeneralSettingsService() {
273
+ await getCachedNextly();
274
+ return container.get("generalSettingsService");
275
+ }
276
+ var updateSettingsSchema = z2.object({
277
+ applicationName: z2.string().max(255).nullable().optional(),
278
+ siteUrl: z2.string().url("Site URL must be a valid URL").max(2048).nullable().optional(),
279
+ adminEmail: z2.string().email("Admin email must be a valid email address").max(255).nullable().optional(),
280
+ timezone: z2.string().max(100).nullable().optional(),
281
+ dateFormat: z2.string().max(50).nullable().optional(),
282
+ timeFormat: z2.string().max(50).nullable().optional(),
283
+ logoUrl: z2.string().url("Logo URL must be a valid URL").max(2048).nullable().optional()
284
+ });
285
+ var getGeneralSettings = withErrorHandler(async (req) => {
286
+ const authResult = await requireAnyPermission(req, [
287
+ { action: "read", resource: "settings" },
288
+ { action: "manage", resource: "settings" }
289
+ ]);
290
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
291
+ const service = await getGeneralSettingsService();
292
+ const settings = await service.getSettings();
293
+ return withTimezoneFormatting(respondData({ ...settings }));
294
+ });
295
+ var updateGeneralSettings = withErrorHandler(async (req) => {
296
+ const authResult = await requireAnyPermission(req, [
297
+ { action: "update", resource: "settings" },
298
+ { action: "manage", resource: "settings" }
299
+ ]);
300
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
301
+ const text = await req.text();
302
+ let body;
303
+ try {
304
+ body = text ? JSON.parse(text) : {};
305
+ } catch {
306
+ throw NextlyError.validation({
307
+ errors: [
308
+ {
309
+ path: "",
310
+ code: "invalid_json",
311
+ message: "Request body is not valid JSON."
312
+ }
313
+ ]
314
+ });
315
+ }
316
+ const parsed = updateSettingsSchema.safeParse(body);
317
+ if (!parsed.success) {
318
+ throw nextlyValidationFromZod(parsed.error);
319
+ }
320
+ const service = await getGeneralSettingsService();
321
+ const updated = await service.updateSettings(parsed.data);
322
+ return withTimezoneFormatting(
323
+ respondMutation("General settings updated.", updated)
324
+ );
325
+ });
326
+
327
+ // src/api/image-sizes.ts
328
+ import { z as z3 } from "zod";
329
+
330
+ // src/services/media-regeneration.ts
331
+ import { and, sql, gt } from "drizzle-orm";
332
+ var MediaRegenerationService = class extends BaseService {
333
+ imageSizeService;
334
+ constructor(adapter, logger) {
335
+ super(adapter, logger);
336
+ this.imageSizeService = new ImageSizeService(adapter, logger);
337
+ }
338
+ /**
339
+ * Check how many images need regeneration.
340
+ *
341
+ * An image needs regeneration if:
342
+ * 1. A configured size is missing from its `sizes` JSONB
343
+ * 2. A configured size has different dimensions than what's stored
344
+ */
345
+ async getRegenerationStatus() {
346
+ const { media } = this.tables;
347
+ const allImages = await this.db.select({ count: sql`count(*)` }).from(media).where(sql`${media.mimeType} LIKE 'image/%'`);
348
+ const total = Number(allImages[0]?.count ?? 0);
349
+ const sizeConfigs = await this.imageSizeService.getActiveSizeConfigs();
350
+ const configNames = sizeConfigs.map((s) => s.name).sort();
351
+ if (configNames.length === 0) {
352
+ return { pending: 0, total, inProgress: false };
353
+ }
354
+ const images = await this.db.select({
355
+ id: media.id,
356
+ sizes: media.sizes
357
+ }).from(media).where(sql`${media.mimeType} LIKE 'image/%'`);
358
+ let pending = 0;
359
+ for (const img of images) {
360
+ if (this.needsRegeneration(img.sizes, configNames)) {
361
+ pending++;
362
+ }
363
+ }
364
+ return { pending, total, inProgress: false };
365
+ }
366
+ /**
367
+ * Process a batch of images that need regeneration.
368
+ *
369
+ * @param options.batchSize - Number of images to process (default: 10)
370
+ * @param options.cursor - ID of last processed image (for pagination)
371
+ */
372
+ async regenerateBatch(options = {}) {
373
+ const batchSize = options.batchSize ?? 10;
374
+ const { media } = this.tables;
375
+ const sizeConfigs = await this.imageSizeService.getActiveSizeConfigs();
376
+ const configNames = sizeConfigs.map((s) => s.name).sort();
377
+ if (configNames.length === 0) {
378
+ return { processed: 0, remaining: 0, nextCursor: null, failures: [] };
379
+ }
380
+ const conditions = [sql`${media.mimeType} LIKE 'image/%'`];
381
+ if (options.cursor) {
382
+ conditions.push(gt(media.id, options.cursor));
383
+ }
384
+ const images = await this.db.select().from(media).where(and(...conditions)).orderBy(media.id).limit(batchSize + 1);
385
+ const hasMore = images.length > batchSize;
386
+ const batch = hasMore ? images.slice(0, batchSize) : images;
387
+ const _storage = getMediaStorage();
388
+ const failures = [];
389
+ let processed = 0;
390
+ for (const img of batch) {
391
+ if (!this.needsRegeneration(img.sizes, configNames)) {
392
+ continue;
393
+ }
394
+ try {
395
+ console.log(
396
+ `[Regeneration] Image ${img.id} needs regeneration (${img.filename})`
397
+ );
398
+ processed++;
399
+ } catch (error) {
400
+ failures.push({
401
+ mediaId: img.id,
402
+ error: error?.message ?? "Unknown error"
403
+ });
404
+ }
405
+ }
406
+ const status = await this.getRegenerationStatus();
407
+ return {
408
+ processed,
409
+ remaining: status.pending - processed,
410
+ nextCursor: hasMore ? batch[batch.length - 1]?.id ?? null : null,
411
+ failures
412
+ };
413
+ }
414
+ needsRegeneration(sizes, configNames) {
415
+ if (!sizes || configNames.length === 0) return configNames.length > 0;
416
+ const parsed = typeof sizes === "string" ? JSON.parse(sizes) : sizes;
417
+ if (!parsed || typeof parsed !== "object") return true;
418
+ const existingNames = Object.keys(parsed).sort();
419
+ for (const name of configNames) {
420
+ if (!existingNames.includes(name)) return true;
421
+ }
422
+ return false;
423
+ }
424
+ };
425
+
426
+ // src/api/image-sizes.ts
427
+ var imageSizeServiceInstance = null;
428
+ async function getImageSizeService() {
429
+ if (!imageSizeServiceInstance) {
430
+ await getCachedNextly();
431
+ const adapter = container.get("adapter");
432
+ imageSizeServiceInstance = new ImageSizeService(adapter, console);
433
+ }
434
+ return imageSizeServiceInstance;
435
+ }
436
+ var createImageSizeSchema = z3.object({
437
+ name: z3.string().min(1).max(50),
438
+ width: z3.number().int().positive().max(1e4).nullable().optional(),
439
+ height: z3.number().int().positive().max(1e4).nullable().optional(),
440
+ fit: z3.enum(["cover", "inside", "contain", "fill"]).optional().default("inside"),
441
+ quality: z3.number().int().min(1).max(100).optional().default(80),
442
+ format: z3.enum(["auto", "webp", "jpeg", "png", "avif"]).optional().default("auto")
443
+ });
444
+ var updateImageSizeSchema = z3.object({
445
+ name: z3.string().min(1).max(50).optional(),
446
+ width: z3.number().int().positive().max(1e4).nullable().optional(),
447
+ height: z3.number().int().positive().max(1e4).nullable().optional(),
448
+ fit: z3.enum(["cover", "inside", "contain", "fill"]).optional(),
449
+ quality: z3.number().int().min(1).max(100).optional(),
450
+ format: z3.enum(["auto", "webp", "jpeg", "png", "avif"]).optional()
451
+ });
452
+ var listImageSizes = withErrorHandler(async (req) => {
453
+ const authResult = await requireAnyPermission(req, [
454
+ { action: "read", resource: "settings" },
455
+ { action: "manage", resource: "settings" }
456
+ ]);
457
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
458
+ const service = await getImageSizeService();
459
+ const sizes = await service.list();
460
+ return respondList(sizes, {
461
+ total: sizes.length,
462
+ page: 1,
463
+ limit: sizes.length,
464
+ totalPages: 1,
465
+ hasNext: false,
466
+ hasPrev: false
467
+ });
468
+ });
469
+ var getImageSizeById = withErrorHandler(
470
+ async (req, id) => {
471
+ const authResult = await requireAnyPermission(req, [
472
+ { action: "read", resource: "settings" },
473
+ { action: "manage", resource: "settings" }
474
+ ]);
475
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
476
+ const service = await getImageSizeService();
477
+ const size = await service.getById(id);
478
+ if (!size) {
479
+ throw NextlyError.notFound({ logContext: { resource: "imageSize", id } });
480
+ }
481
+ return respondDoc(size);
482
+ }
483
+ );
484
+ var createImageSize = withErrorHandler(async (req) => {
485
+ const authResult = await requireAnyPermission(req, [
486
+ { action: "manage", resource: "settings" }
487
+ ]);
488
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
489
+ const text = await req.text();
490
+ let body;
491
+ try {
492
+ body = text ? JSON.parse(text) : {};
493
+ } catch {
494
+ throw NextlyError.validation({
495
+ errors: [
496
+ {
497
+ path: "",
498
+ code: "invalid_json",
499
+ message: "Request body is not valid JSON."
500
+ }
501
+ ]
502
+ });
503
+ }
504
+ const parsed = createImageSizeSchema.safeParse(body);
505
+ if (!parsed.success) {
506
+ throw nextlyValidationFromZod(parsed.error);
507
+ }
508
+ const data = parsed.data;
509
+ if (!data.width && !data.height) {
510
+ throw NextlyError.validation({
511
+ errors: [
512
+ {
513
+ path: "",
514
+ code: "missing_dimension",
515
+ message: "At least one dimension (width or height) is required."
516
+ }
517
+ ]
518
+ });
519
+ }
520
+ const service = await getImageSizeService();
521
+ const created = await service.create({
522
+ name: data.name,
523
+ width: data.width ?? null,
524
+ height: data.height ?? null,
525
+ fit: data.fit,
526
+ quality: data.quality,
527
+ format: data.format,
528
+ isDefault: false
529
+ // UI-created sizes are not "default" (code-defined)
530
+ });
531
+ return respondMutation("Image size created.", created, { status: 201 });
532
+ });
533
+ var updateImageSize = withErrorHandler(
534
+ async (req, id) => {
535
+ const authResult = await requireAnyPermission(req, [
536
+ { action: "manage", resource: "settings" }
537
+ ]);
538
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
539
+ const text = await req.text();
540
+ let body;
541
+ try {
542
+ body = text ? JSON.parse(text) : {};
543
+ } catch {
544
+ throw NextlyError.validation({
545
+ errors: [
546
+ {
547
+ path: "",
548
+ code: "invalid_json",
549
+ message: "Request body is not valid JSON."
550
+ }
551
+ ]
552
+ });
553
+ }
554
+ const parsed = updateImageSizeSchema.safeParse(body);
555
+ if (!parsed.success) {
556
+ throw nextlyValidationFromZod(parsed.error);
557
+ }
558
+ const service = await getImageSizeService();
559
+ const updated = await service.update(id, parsed.data);
560
+ return respondMutation("Image size updated.", updated);
561
+ }
562
+ );
563
+ var deleteImageSize = withErrorHandler(
564
+ async (req, id) => {
565
+ const authResult = await requireAnyPermission(req, [
566
+ { action: "manage", resource: "settings" }
567
+ ]);
568
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
569
+ const service = await getImageSizeService();
570
+ await service.delete(id);
571
+ return respondAction("Image size deleted.", { id });
572
+ }
573
+ );
574
+ var getRegenerationStatus = withErrorHandler(async (req) => {
575
+ const authResult = await requireAnyPermission(req, [
576
+ { action: "manage", resource: "settings" }
577
+ ]);
578
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
579
+ await getCachedNextly();
580
+ const adapter = container.get("adapter");
581
+ const regenService = new MediaRegenerationService(adapter, console);
582
+ const status = await regenService.getRegenerationStatus();
583
+ return respondData(status);
584
+ });
585
+ var regenerateBatch = withErrorHandler(async (req) => {
586
+ const authResult = await requireAnyPermission(req, [
587
+ { action: "manage", resource: "settings" }
588
+ ]);
589
+ if (isErrorResponse(authResult)) throw toNextlyAuthError(authResult);
590
+ const text = await req.text();
591
+ let body;
592
+ try {
593
+ body = text ? JSON.parse(text) : {};
594
+ } catch {
595
+ throw NextlyError.validation({
596
+ errors: [
597
+ {
598
+ path: "",
599
+ code: "invalid_json",
600
+ message: "Request body is not valid JSON."
601
+ }
602
+ ]
603
+ });
604
+ }
605
+ const opts = body && typeof body === "object" ? body : {};
606
+ const batchSize = typeof opts.batchSize === "number" ? opts.batchSize : 10;
607
+ const cursor = typeof opts.cursor === "string" ? opts.cursor : void 0;
608
+ await getCachedNextly();
609
+ const adapter = container.get("adapter");
610
+ const regenService = new MediaRegenerationService(adapter, console);
611
+ const result = await regenService.regenerateBatch({ batchSize, cursor });
612
+ return respondAction("Regeneration batch processed.", {
613
+ processed: result.processed,
614
+ remaining: result.remaining,
615
+ nextCursor: result.nextCursor,
616
+ failures: result.failures
617
+ });
618
+ });
619
+
620
+ // src/domains/schema/journal/read-journal.ts
621
+ import { desc, lt } from "drizzle-orm";
622
+ var MIN_LIMIT = 1;
623
+ var MAX_LIMIT = 100;
624
+ async function readJournal(args) {
625
+ const table = tableForDialect(args.dialect);
626
+ const limit = clamp(args.limit, MIN_LIMIT, MAX_LIMIT);
627
+ const beforeDate = args.before ? new Date(args.before) : void 0;
628
+ const db = args.db;
629
+ const startedAtCol = table.startedAt;
630
+ let chain = db.select().from(table);
631
+ if (beforeDate) {
632
+ chain = chain.where(lt(startedAtCol, beforeDate));
633
+ }
634
+ chain = chain.orderBy(desc(startedAtCol));
635
+ const raw = await chain.limit(limit + 1);
636
+ const trimmed = raw.slice(0, limit);
637
+ const hasMore = raw.length > limit;
638
+ return { rows: trimmed.map(mapRow), hasMore };
639
+ }
640
+ function clamp(n, lo, hi) {
641
+ return Math.max(lo, Math.min(hi, n));
642
+ }
643
+ function mapRow(r) {
644
+ const scopeKind = r.scopeKind;
645
+ const scopeSlug = r.scopeSlug;
646
+ let scope = null;
647
+ if (scopeKind === "fresh-push") {
648
+ scope = { kind: "fresh-push" };
649
+ } else if (scopeKind === "global") {
650
+ scope = scopeSlug ? { kind: "global", slug: scopeSlug } : { kind: "global" };
651
+ } else if ((scopeKind === "collection" || scopeKind === "single") && typeof scopeSlug === "string") {
652
+ scope = { kind: scopeKind, slug: scopeSlug };
653
+ }
654
+ const sa = r.summaryAdded;
655
+ const sr = r.summaryRemoved;
656
+ const srn = r.summaryRenamed;
657
+ const sc = r.summaryChanged;
658
+ const summary = sa !== null && sr !== null && srn !== null && sc !== null ? { added: sa, removed: sr, renamed: srn, changed: sc } : null;
659
+ return {
660
+ id: String(r.id),
661
+ source: r.source,
662
+ status: r.status,
663
+ scope,
664
+ summary,
665
+ startedAt: toIso(r.startedAt),
666
+ endedAt: r.endedAt != null ? toIso(r.endedAt) : null,
667
+ durationMs: r.durationMs ?? null,
668
+ errorCode: r.errorCode ?? null,
669
+ errorMessage: r.errorMessage ?? null
670
+ };
671
+ }
672
+ function toIso(v) {
673
+ if (v instanceof Date) return v.toISOString();
674
+ if (typeof v === "number") return new Date(v).toISOString();
675
+ if (typeof v === "string") return new Date(v).toISOString();
676
+ return String(v);
677
+ }
678
+ function tableForDialect(dialect) {
679
+ switch (dialect) {
680
+ case "postgresql":
681
+ return nextlyMigrationJournalPg;
682
+ case "mysql":
683
+ return nextlyMigrationJournalMysql;
684
+ case "sqlite":
685
+ return nextlyMigrationJournalSqlite;
686
+ default: {
687
+ const exhaustive = dialect;
688
+ throw new Error(`Unsupported dialect: ${String(exhaustive)}`);
689
+ }
690
+ }
691
+ }
692
+
693
+ // src/api/schema-journal.ts
694
+ var PRIVATE_NO_STORE_HEADERS2 = {
695
+ "Cache-Control": "private, no-store",
696
+ Vary: "Cookie"
697
+ };
698
+ var DEFAULT_LIMIT = 20;
699
+ var MIN_LIMIT2 = 1;
700
+ var MAX_LIMIT2 = 100;
701
+ async function getAdapter() {
702
+ await getCachedNextly();
703
+ return container.get("adapter");
704
+ }
705
+ var getSchemaJournal = withErrorHandler(async (req) => {
706
+ const auth = await requireAuthentication(req);
707
+ if (isErrorResponse(auth)) throw toNextlyAuthError(auth);
708
+ if (!await isSuperAdmin(auth.userId)) {
709
+ throw NextlyError.forbidden({
710
+ logContext: { reason: "schema-journal-super-admin-required" }
711
+ });
712
+ }
713
+ const { searchParams } = new URL(req.url);
714
+ const limitParam = searchParams.get("limit");
715
+ let limit = DEFAULT_LIMIT;
716
+ if (limitParam !== null) {
717
+ const parsed = Number(limitParam);
718
+ if (!Number.isFinite(parsed) || parsed < MIN_LIMIT2 || parsed > MAX_LIMIT2) {
719
+ throw NextlyError.validation({
720
+ errors: [
721
+ {
722
+ path: "limit",
723
+ code: "out_of_range",
724
+ message: `limit must be a number between ${MIN_LIMIT2} and ${MAX_LIMIT2}`
725
+ }
726
+ ]
727
+ });
728
+ }
729
+ limit = Math.floor(parsed);
730
+ }
731
+ const beforeParam = searchParams.get("before");
732
+ let before;
733
+ if (beforeParam !== null) {
734
+ const parsed = new Date(beforeParam);
735
+ if (Number.isNaN(parsed.getTime())) {
736
+ throw NextlyError.validation({
737
+ errors: [
738
+ {
739
+ path: "before",
740
+ code: "invalid_date",
741
+ message: "before must be a valid ISO 8601 timestamp"
742
+ }
743
+ ]
744
+ });
745
+ }
746
+ before = beforeParam;
747
+ }
748
+ const adapter = await getAdapter();
749
+ const db = adapter.getDrizzle();
750
+ const result = await readJournal({
751
+ db,
752
+ dialect: adapter.dialect,
753
+ limit,
754
+ before
755
+ });
756
+ return respondData({ ...result }, { headers: PRIVATE_NO_STORE_HEADERS2 });
757
+ });
758
+
759
+ // src/route-handler/route-parser.ts
760
+ function getActionFromMethod(httpMethod) {
761
+ switch (httpMethod) {
762
+ case "GET":
763
+ return "read";
764
+ case "POST":
765
+ return "create";
766
+ case "PATCH":
767
+ case "PUT":
768
+ return "update";
769
+ case "DELETE":
770
+ return "delete";
771
+ default:
772
+ return "read";
773
+ }
774
+ }
775
+ function isPublicEndpoint(service, method) {
776
+ if (service === "auth") {
777
+ return [
778
+ "register",
779
+ "generatePasswordResetToken",
780
+ "resetPasswordWithToken",
781
+ "verifyEmail"
782
+ ].includes(method);
783
+ }
784
+ if (service === "forms") {
785
+ return true;
786
+ }
787
+ if (service === "components" && method === "listComponents") {
788
+ return true;
789
+ }
790
+ return false;
791
+ }
792
+ function requiresAuthOnly(service, method) {
793
+ if (service === "auth") {
794
+ return ["changePassword", "generateEmailVerificationToken"].includes(
795
+ method
796
+ );
797
+ }
798
+ if (service === "collections" && ["listCollections"].includes(method)) {
799
+ return true;
800
+ }
801
+ if (service === "singles" && ["listSingles"].includes(method)) {
802
+ return true;
803
+ }
804
+ if (service === "components" && method === "getComponent") {
805
+ return true;
806
+ }
807
+ return false;
808
+ }
809
+ function getActionFromOperation(operation) {
810
+ switch (operation) {
811
+ case "create":
812
+ return "create";
813
+ case "update":
814
+ return "update";
815
+ case "delete":
816
+ return "delete";
817
+ default:
818
+ return "read";
819
+ }
820
+ }
821
+ function parseMeRoutes(httpMethod, subresource, routeParams) {
822
+ if (subresource === "permissions" && httpMethod === "GET") {
823
+ return {
824
+ service: "users",
825
+ operation: "list",
826
+ method: "getCurrentUserPermissions",
827
+ routeParams
828
+ };
829
+ }
830
+ if (subresource) {
831
+ return null;
832
+ }
833
+ if (httpMethod === "GET") {
834
+ return {
835
+ service: "users",
836
+ operation: "single",
837
+ method: "getCurrentUser",
838
+ routeParams
839
+ };
840
+ }
841
+ if (httpMethod === "PATCH") {
842
+ return {
843
+ service: "users",
844
+ operation: "update",
845
+ method: "updateCurrentUser",
846
+ routeParams
847
+ };
848
+ }
849
+ return null;
850
+ }
851
+ function parseUserRoutes(id, subresource, subId, additionalParams, httpMethod, routeParams) {
852
+ if (!id && httpMethod === "POST") {
853
+ return {
854
+ service: "users",
855
+ operation: "create",
856
+ method: "createLocalUser",
857
+ routeParams
858
+ };
859
+ }
860
+ if (!id && httpMethod === "GET") {
861
+ return {
862
+ service: "users",
863
+ operation: "list",
864
+ method: "listUsers",
865
+ routeParams
866
+ };
867
+ }
868
+ if (id && !subresource && httpMethod === "GET") {
869
+ routeParams.userId = id;
870
+ return {
871
+ service: "users",
872
+ operation: "single",
873
+ method: "getUserById",
874
+ routeParams
875
+ };
876
+ }
877
+ if (id && !subresource && httpMethod === "PATCH") {
878
+ routeParams.userId = id;
879
+ return {
880
+ service: "users",
881
+ operation: "update",
882
+ method: "updateUser",
883
+ routeParams
884
+ };
885
+ }
886
+ if (id && !subresource && httpMethod === "DELETE") {
887
+ routeParams.userId = id;
888
+ return {
889
+ service: "users",
890
+ operation: "delete",
891
+ method: "deleteUser",
892
+ routeParams
893
+ };
894
+ }
895
+ if (id && subresource === "password" && httpMethod === "PATCH") {
896
+ routeParams.userId = id;
897
+ return {
898
+ service: "users",
899
+ operation: "update",
900
+ method: "updatePasswordHash",
901
+ routeParams
902
+ };
903
+ }
904
+ if (id && subresource === "accounts" && !subId && httpMethod === "GET") {
905
+ routeParams.userId = id;
906
+ return {
907
+ service: "users",
908
+ operation: "single",
909
+ method: "getAccounts",
910
+ routeParams
911
+ };
912
+ }
913
+ if (id && subresource === "accounts" && subId && additionalParams[0] && httpMethod === "DELETE") {
914
+ routeParams.userId = id;
915
+ routeParams.provider = subId;
916
+ routeParams.providerAccountId = additionalParams[0];
917
+ return {
918
+ service: "users",
919
+ operation: "update",
920
+ method: "unlinkAccountForUser",
921
+ routeParams
922
+ };
923
+ }
924
+ if (id && subresource === "roles" && !subId && httpMethod === "POST") {
925
+ routeParams.userId = id;
926
+ return {
927
+ service: "rbac",
928
+ operation: "update",
929
+ method: "assignRoleToUser",
930
+ routeParams
931
+ };
932
+ }
933
+ if (id && subresource === "roles" && !subId && httpMethod === "GET") {
934
+ routeParams.userId = id;
935
+ return {
936
+ service: "rbac",
937
+ operation: "list",
938
+ method: "listUserRoles",
939
+ routeParams
940
+ };
941
+ }
942
+ if (id && subresource === "roles" && subId && httpMethod === "DELETE") {
943
+ routeParams.userId = id;
944
+ routeParams.roleId = subId;
945
+ return {
946
+ service: "rbac",
947
+ operation: "update",
948
+ method: "unassignRoleFromUser",
949
+ routeParams
950
+ };
951
+ }
952
+ return null;
953
+ }
954
+ function parseRoleRoutes(id, subresource, subId, httpMethod, routeParams) {
955
+ if (!id && httpMethod === "POST") {
956
+ return {
957
+ service: "rbac",
958
+ operation: "create",
959
+ method: "createRole",
960
+ routeParams
961
+ };
962
+ }
963
+ if (!id && httpMethod === "GET") {
964
+ return {
965
+ service: "rbac",
966
+ operation: "list",
967
+ method: "listRoles",
968
+ routeParams
969
+ };
970
+ }
971
+ if (id && !subresource && httpMethod === "GET") {
972
+ routeParams.roleId = id;
973
+ return {
974
+ service: "rbac",
975
+ operation: "single",
976
+ method: "getRoleById",
977
+ routeParams
978
+ };
979
+ }
980
+ if (id && !subresource && httpMethod === "PATCH") {
981
+ routeParams.roleId = id;
982
+ return {
983
+ service: "rbac",
984
+ operation: "update",
985
+ method: "updateRole",
986
+ routeParams
987
+ };
988
+ }
989
+ if (id && !subresource && httpMethod === "DELETE") {
990
+ routeParams.roleId = id;
991
+ return {
992
+ service: "rbac",
993
+ operation: "delete",
994
+ method: "deleteRole",
995
+ routeParams
996
+ };
997
+ }
998
+ if (id && subresource === "children" && !subId && httpMethod === "POST") {
999
+ routeParams.parentRoleId = id;
1000
+ return {
1001
+ service: "rbac",
1002
+ operation: "update",
1003
+ method: "addRoleInheritance",
1004
+ routeParams
1005
+ };
1006
+ }
1007
+ if (id && subresource === "children" && !subId && httpMethod === "GET") {
1008
+ routeParams.roleId = id;
1009
+ return {
1010
+ service: "rbac",
1011
+ operation: "list",
1012
+ method: "listDescendantRoles",
1013
+ routeParams
1014
+ };
1015
+ }
1016
+ if (id && subresource === "children" && subId && httpMethod === "DELETE") {
1017
+ routeParams.parentRoleId = id;
1018
+ routeParams.childRoleId = subId;
1019
+ return {
1020
+ service: "rbac",
1021
+ operation: "update",
1022
+ method: "removeRoleInheritance",
1023
+ routeParams
1024
+ };
1025
+ }
1026
+ if (id && subresource === "parents" && httpMethod === "GET") {
1027
+ routeParams.roleId = id;
1028
+ return {
1029
+ service: "rbac",
1030
+ operation: "list",
1031
+ method: "listAncestorRoles",
1032
+ routeParams
1033
+ };
1034
+ }
1035
+ if (id && subresource === "permissions" && !subId && httpMethod === "PATCH") {
1036
+ routeParams.roleId = id;
1037
+ return {
1038
+ service: "rbac",
1039
+ operation: "update",
1040
+ method: "setRolePermissions",
1041
+ routeParams
1042
+ };
1043
+ }
1044
+ if (id && subresource === "permissions" && !subId && httpMethod === "POST") {
1045
+ routeParams.roleId = id;
1046
+ return {
1047
+ service: "rbac",
1048
+ operation: "update",
1049
+ method: "addPermissionToRole",
1050
+ routeParams
1051
+ };
1052
+ }
1053
+ if (id && subresource === "permissions" && !subId && httpMethod === "GET") {
1054
+ routeParams.roleId = id;
1055
+ return {
1056
+ service: "rbac",
1057
+ operation: "list",
1058
+ method: "listRolePermissions",
1059
+ routeParams
1060
+ };
1061
+ }
1062
+ if (id && subresource === "permissions" && subId && httpMethod === "DELETE") {
1063
+ routeParams.roleId = id;
1064
+ routeParams.permissionId = subId;
1065
+ return {
1066
+ service: "rbac",
1067
+ operation: "update",
1068
+ method: "removePermissionFromRole",
1069
+ routeParams
1070
+ };
1071
+ }
1072
+ return null;
1073
+ }
1074
+ function parseCollectionRoutes(id, subresource, subId, httpMethod, routeParams, additionalParams = []) {
1075
+ const bulkDeleteRoute = parseCollectionEntryBulkDeleteRoute(
1076
+ id,
1077
+ subresource,
1078
+ subId,
1079
+ httpMethod,
1080
+ routeParams
1081
+ );
1082
+ if (bulkDeleteRoute) return bulkDeleteRoute;
1083
+ const bulkUpdateRoute = parseCollectionEntryBulkUpdateRoute(
1084
+ id,
1085
+ subresource,
1086
+ subId,
1087
+ httpMethod,
1088
+ routeParams
1089
+ );
1090
+ if (bulkUpdateRoute) return bulkUpdateRoute;
1091
+ const bulkUpdateByQueryRoute = parseCollectionEntryBulkUpdateByQueryRoute(
1092
+ id,
1093
+ subresource,
1094
+ subId,
1095
+ httpMethod,
1096
+ routeParams
1097
+ );
1098
+ if (bulkUpdateByQueryRoute) return bulkUpdateByQueryRoute;
1099
+ const duplicateRoute = parseCollectionEntryDuplicateRoute(
1100
+ id,
1101
+ subresource,
1102
+ subId,
1103
+ additionalParams,
1104
+ httpMethod,
1105
+ routeParams
1106
+ );
1107
+ if (duplicateRoute) return duplicateRoute;
1108
+ const countRoute = parseCollectionEntryCountRoute(
1109
+ id,
1110
+ subresource,
1111
+ subId,
1112
+ httpMethod,
1113
+ routeParams
1114
+ );
1115
+ if (countRoute) return countRoute;
1116
+ if (!id && httpMethod === "POST") {
1117
+ return {
1118
+ service: "collections",
1119
+ operation: "create",
1120
+ method: "createCollection",
1121
+ routeParams
1122
+ };
1123
+ }
1124
+ if (!id && httpMethod === "GET") {
1125
+ return {
1126
+ service: "collections",
1127
+ operation: "list",
1128
+ method: "listCollections",
1129
+ routeParams
1130
+ };
1131
+ }
1132
+ if (id === "schema" && subresource && subId === "preview" && httpMethod === "POST") {
1133
+ routeParams.collectionName = subresource;
1134
+ return {
1135
+ service: "collections",
1136
+ operation: "single",
1137
+ method: "previewSchemaChanges",
1138
+ routeParams
1139
+ };
1140
+ }
1141
+ if (id === "schema" && subresource && subId === "apply" && httpMethod === "POST") {
1142
+ routeParams.collectionName = subresource;
1143
+ return {
1144
+ service: "collections",
1145
+ operation: "update",
1146
+ method: "applySchemaChanges",
1147
+ routeParams
1148
+ };
1149
+ }
1150
+ if (id === "schema" && subresource && httpMethod === "GET") {
1151
+ routeParams.collectionName = subresource;
1152
+ return {
1153
+ service: "collections",
1154
+ operation: "single",
1155
+ method: "getCollection",
1156
+ routeParams
1157
+ };
1158
+ }
1159
+ if (id && !subresource && httpMethod === "GET") {
1160
+ routeParams.collectionName = id;
1161
+ return {
1162
+ service: "collections",
1163
+ operation: "single",
1164
+ method: "getCollection",
1165
+ routeParams
1166
+ };
1167
+ }
1168
+ if (id && !subresource && httpMethod === "PATCH") {
1169
+ routeParams.collectionName = id;
1170
+ return {
1171
+ service: "collections",
1172
+ operation: "update",
1173
+ method: "updateCollection",
1174
+ routeParams
1175
+ };
1176
+ }
1177
+ if (id && !subresource && httpMethod === "DELETE") {
1178
+ routeParams.collectionName = id;
1179
+ return {
1180
+ service: "collections",
1181
+ operation: "delete",
1182
+ method: "deleteCollection",
1183
+ routeParams
1184
+ };
1185
+ }
1186
+ if (id && subresource === "entries" && !subId && httpMethod === "GET") {
1187
+ routeParams.collectionName = id;
1188
+ return {
1189
+ service: "collections",
1190
+ operation: "list",
1191
+ method: "listEntries",
1192
+ routeParams
1193
+ };
1194
+ }
1195
+ if (id && subresource === "entries" && !subId && httpMethod === "POST") {
1196
+ routeParams.collectionName = id;
1197
+ return {
1198
+ service: "collections",
1199
+ operation: "create",
1200
+ method: "createEntry",
1201
+ routeParams
1202
+ };
1203
+ }
1204
+ if (id && subresource === "entries" && subId && httpMethod === "GET") {
1205
+ routeParams.collectionName = id;
1206
+ routeParams.entryId = subId;
1207
+ return {
1208
+ service: "collections",
1209
+ operation: "single",
1210
+ method: "getEntry",
1211
+ routeParams
1212
+ };
1213
+ }
1214
+ if (id && subresource === "entries" && subId && httpMethod === "PATCH") {
1215
+ routeParams.collectionName = id;
1216
+ routeParams.entryId = subId;
1217
+ return {
1218
+ service: "collections",
1219
+ operation: "update",
1220
+ method: "updateEntry",
1221
+ routeParams
1222
+ };
1223
+ }
1224
+ if (id && subresource === "entries" && subId && httpMethod === "DELETE") {
1225
+ routeParams.collectionName = id;
1226
+ routeParams.entryId = subId;
1227
+ return {
1228
+ service: "collections",
1229
+ operation: "delete",
1230
+ method: "deleteEntry",
1231
+ routeParams
1232
+ };
1233
+ }
1234
+ return null;
1235
+ }
1236
+ function parseCollectionEntryDuplicateRoute(id, subresource, subId, additionalParams, httpMethod, routeParams) {
1237
+ if (id && subresource === "entries" && subId && additionalParams[0] === "duplicate" && httpMethod === "POST") {
1238
+ routeParams.collectionName = id;
1239
+ routeParams.entryId = subId;
1240
+ return {
1241
+ service: "collections",
1242
+ operation: "create",
1243
+ method: "duplicateEntry",
1244
+ routeParams
1245
+ };
1246
+ }
1247
+ return null;
1248
+ }
1249
+ function parseCollectionEntryBulkDeleteRoute(id, subresource, subId, httpMethod, routeParams) {
1250
+ if (id && subresource === "entries" && subId === "bulk-delete" && httpMethod === "POST") {
1251
+ routeParams.collectionName = id;
1252
+ return {
1253
+ service: "collections",
1254
+ operation: "delete",
1255
+ method: "bulkDeleteEntries",
1256
+ routeParams
1257
+ };
1258
+ }
1259
+ return null;
1260
+ }
1261
+ function parseCollectionEntryBulkUpdateRoute(id, subresource, subId, httpMethod, routeParams) {
1262
+ if (id && subresource === "entries" && subId === "bulk-update" && httpMethod === "POST") {
1263
+ routeParams.collectionName = id;
1264
+ return {
1265
+ service: "collections",
1266
+ operation: "update",
1267
+ method: "bulkUpdateEntries",
1268
+ routeParams
1269
+ };
1270
+ }
1271
+ return null;
1272
+ }
1273
+ function parseCollectionEntryBulkUpdateByQueryRoute(id, subresource, subId, httpMethod, routeParams) {
1274
+ if (id && subresource === "entries" && !subId && httpMethod === "PATCH") {
1275
+ routeParams.collectionName = id;
1276
+ return {
1277
+ service: "collections",
1278
+ operation: "update",
1279
+ method: "bulkUpdateByQuery",
1280
+ routeParams
1281
+ };
1282
+ }
1283
+ return null;
1284
+ }
1285
+ function parseCollectionEntryCountRoute(id, subresource, subId, httpMethod, routeParams) {
1286
+ if (id && subresource === "entries" && subId === "count" && httpMethod === "GET") {
1287
+ routeParams.collectionName = id;
1288
+ return {
1289
+ service: "collections",
1290
+ operation: "count",
1291
+ method: "countEntries",
1292
+ routeParams
1293
+ };
1294
+ }
1295
+ return null;
1296
+ }
1297
+ function parsePermissionRoutes(id, httpMethod, routeParams) {
1298
+ if (!id && httpMethod === "POST") {
1299
+ return {
1300
+ service: "rbac",
1301
+ operation: "create",
1302
+ method: "ensurePermission",
1303
+ routeParams
1304
+ };
1305
+ }
1306
+ if (!id && httpMethod === "GET") {
1307
+ return {
1308
+ service: "rbac",
1309
+ operation: "list",
1310
+ method: "listPermissions",
1311
+ routeParams
1312
+ };
1313
+ }
1314
+ if (id && httpMethod === "GET") {
1315
+ routeParams.permissionId = id;
1316
+ return {
1317
+ service: "rbac",
1318
+ operation: "single",
1319
+ method: "getPermissionById",
1320
+ routeParams
1321
+ };
1322
+ }
1323
+ if (id && httpMethod === "PATCH") {
1324
+ routeParams.permissionId = id;
1325
+ return {
1326
+ service: "rbac",
1327
+ operation: "update",
1328
+ method: "updatePermission",
1329
+ routeParams
1330
+ };
1331
+ }
1332
+ if (id && httpMethod === "DELETE") {
1333
+ routeParams.permissionId = id;
1334
+ return {
1335
+ service: "rbac",
1336
+ operation: "delete",
1337
+ method: "deletePermissionById",
1338
+ routeParams
1339
+ };
1340
+ }
1341
+ return null;
1342
+ }
1343
+ function parseSingleRoutes(id, subresource, subId, httpMethod, routeParams) {
1344
+ if (!id && httpMethod === "GET") {
1345
+ return {
1346
+ service: "singles",
1347
+ operation: "list",
1348
+ method: "listSingles",
1349
+ routeParams
1350
+ };
1351
+ }
1352
+ if (!id && httpMethod === "POST") {
1353
+ return {
1354
+ service: "singles",
1355
+ operation: "create",
1356
+ method: "createSingle",
1357
+ routeParams
1358
+ };
1359
+ }
1360
+ if (id && !subresource && httpMethod === "GET") {
1361
+ routeParams.slug = id;
1362
+ return {
1363
+ service: "singles",
1364
+ operation: "single",
1365
+ method: "getSingleDocument",
1366
+ routeParams
1367
+ };
1368
+ }
1369
+ if (id && !subresource && httpMethod === "PATCH") {
1370
+ routeParams.slug = id;
1371
+ return {
1372
+ service: "singles",
1373
+ operation: "update",
1374
+ method: "updateSingleDocument",
1375
+ routeParams
1376
+ };
1377
+ }
1378
+ if (id && !subresource && httpMethod === "DELETE") {
1379
+ routeParams.slug = id;
1380
+ return {
1381
+ service: "singles",
1382
+ operation: "delete",
1383
+ method: "deleteSingle",
1384
+ routeParams
1385
+ };
1386
+ }
1387
+ if (id && subresource === "schema" && httpMethod === "GET") {
1388
+ routeParams.slug = id;
1389
+ return {
1390
+ service: "singles",
1391
+ operation: "single",
1392
+ method: "getSingleSchema",
1393
+ routeParams
1394
+ };
1395
+ }
1396
+ if (id && subresource === "schema" && httpMethod === "PATCH") {
1397
+ routeParams.slug = id;
1398
+ return {
1399
+ service: "singles",
1400
+ operation: "update",
1401
+ method: "updateSingleSchema",
1402
+ routeParams
1403
+ };
1404
+ }
1405
+ if (id === "schema" && subresource && subId === "preview" && httpMethod === "POST") {
1406
+ routeParams.slug = subresource;
1407
+ return {
1408
+ service: "singles",
1409
+ operation: "single",
1410
+ method: "previewSingleSchemaChanges",
1411
+ routeParams
1412
+ };
1413
+ }
1414
+ if (id === "schema" && subresource && subId === "apply" && httpMethod === "POST") {
1415
+ routeParams.slug = subresource;
1416
+ return {
1417
+ service: "singles",
1418
+ operation: "update",
1419
+ method: "applySingleSchemaChanges",
1420
+ routeParams
1421
+ };
1422
+ }
1423
+ return null;
1424
+ }
1425
+ function parseComponentRoutes(id, httpMethod, routeParams, subresource, subId) {
1426
+ if (id === "schema" && subresource && subId === "preview" && httpMethod === "POST") {
1427
+ routeParams.slug = subresource;
1428
+ return {
1429
+ service: "components",
1430
+ operation: "single",
1431
+ method: "previewComponentSchemaChanges",
1432
+ routeParams
1433
+ };
1434
+ }
1435
+ if (id === "schema" && subresource && subId === "apply" && httpMethod === "POST") {
1436
+ routeParams.slug = subresource;
1437
+ return {
1438
+ service: "components",
1439
+ operation: "update",
1440
+ method: "applyComponentSchemaChanges",
1441
+ routeParams
1442
+ };
1443
+ }
1444
+ const slug = id;
1445
+ if (!slug && httpMethod === "GET") {
1446
+ return {
1447
+ service: "components",
1448
+ operation: "list",
1449
+ method: "listComponents",
1450
+ routeParams
1451
+ };
1452
+ }
1453
+ if (!slug && httpMethod === "POST") {
1454
+ return {
1455
+ service: "components",
1456
+ operation: "create",
1457
+ method: "createComponent",
1458
+ routeParams
1459
+ };
1460
+ }
1461
+ if (slug && httpMethod === "GET") {
1462
+ routeParams.slug = slug;
1463
+ return {
1464
+ service: "components",
1465
+ operation: "single",
1466
+ method: "getComponent",
1467
+ routeParams
1468
+ };
1469
+ }
1470
+ if (slug && httpMethod === "PATCH") {
1471
+ routeParams.slug = slug;
1472
+ return {
1473
+ service: "components",
1474
+ operation: "update",
1475
+ method: "updateComponent",
1476
+ routeParams
1477
+ };
1478
+ }
1479
+ if (slug && httpMethod === "DELETE") {
1480
+ routeParams.slug = slug;
1481
+ return {
1482
+ service: "components",
1483
+ operation: "delete",
1484
+ method: "deleteComponent",
1485
+ routeParams
1486
+ };
1487
+ }
1488
+ return null;
1489
+ }
1490
+ function parseFormsRoutes(slug, action, httpMethod, routeParams) {
1491
+ if (!slug && httpMethod === "GET") {
1492
+ return {
1493
+ service: "forms",
1494
+ operation: "list",
1495
+ method: "listForms",
1496
+ routeParams
1497
+ };
1498
+ }
1499
+ if (slug && !action && httpMethod === "GET") {
1500
+ routeParams.slug = slug;
1501
+ return {
1502
+ service: "forms",
1503
+ operation: "single",
1504
+ method: "getFormBySlug",
1505
+ routeParams
1506
+ };
1507
+ }
1508
+ if (slug && action === "submit" && httpMethod === "POST") {
1509
+ routeParams.slug = slug;
1510
+ return {
1511
+ service: "forms",
1512
+ operation: "create",
1513
+ method: "submitForm",
1514
+ routeParams
1515
+ };
1516
+ }
1517
+ return null;
1518
+ }
1519
+ function parseEmailProviderRoutes(id, subresource, httpMethod, routeParams) {
1520
+ if (!id && httpMethod === "GET") {
1521
+ return {
1522
+ service: "emailProviders",
1523
+ operation: "list",
1524
+ method: "listProviders",
1525
+ routeParams
1526
+ };
1527
+ }
1528
+ if (!id && httpMethod === "POST") {
1529
+ return {
1530
+ service: "emailProviders",
1531
+ operation: "create",
1532
+ method: "createProvider",
1533
+ routeParams
1534
+ };
1535
+ }
1536
+ if (id && subresource === "default" && httpMethod === "PATCH") {
1537
+ routeParams.providerId = id;
1538
+ return {
1539
+ service: "emailProviders",
1540
+ operation: "update",
1541
+ method: "setDefault",
1542
+ routeParams
1543
+ };
1544
+ }
1545
+ if (id && subresource === "test" && httpMethod === "POST") {
1546
+ routeParams.providerId = id;
1547
+ return {
1548
+ service: "emailProviders",
1549
+ operation: "single",
1550
+ method: "testProvider",
1551
+ routeParams
1552
+ };
1553
+ }
1554
+ if (id && !subresource && httpMethod === "GET") {
1555
+ routeParams.providerId = id;
1556
+ return {
1557
+ service: "emailProviders",
1558
+ operation: "single",
1559
+ method: "getProvider",
1560
+ routeParams
1561
+ };
1562
+ }
1563
+ if (id && !subresource && httpMethod === "PATCH") {
1564
+ routeParams.providerId = id;
1565
+ return {
1566
+ service: "emailProviders",
1567
+ operation: "update",
1568
+ method: "updateProvider",
1569
+ routeParams
1570
+ };
1571
+ }
1572
+ if (id && !subresource && httpMethod === "DELETE") {
1573
+ routeParams.providerId = id;
1574
+ return {
1575
+ service: "emailProviders",
1576
+ operation: "delete",
1577
+ method: "deleteProvider",
1578
+ routeParams
1579
+ };
1580
+ }
1581
+ return null;
1582
+ }
1583
+ function parseEmailTemplateRoutes(id, subresource, httpMethod, routeParams) {
1584
+ if (!id && httpMethod === "GET") {
1585
+ return {
1586
+ service: "emailTemplates",
1587
+ operation: "list",
1588
+ method: "listTemplates",
1589
+ routeParams
1590
+ };
1591
+ }
1592
+ if (!id && httpMethod === "POST") {
1593
+ return {
1594
+ service: "emailTemplates",
1595
+ operation: "create",
1596
+ method: "createTemplate",
1597
+ routeParams
1598
+ };
1599
+ }
1600
+ if (id === "layout" && !subresource && httpMethod === "GET") {
1601
+ return {
1602
+ service: "emailTemplates",
1603
+ operation: "single",
1604
+ method: "getLayout",
1605
+ routeParams
1606
+ };
1607
+ }
1608
+ if (id === "layout" && !subresource && httpMethod === "PATCH") {
1609
+ return {
1610
+ service: "emailTemplates",
1611
+ operation: "update",
1612
+ method: "updateLayout",
1613
+ routeParams
1614
+ };
1615
+ }
1616
+ if (id && subresource === "preview" && httpMethod === "POST") {
1617
+ routeParams.templateId = id;
1618
+ return {
1619
+ service: "emailTemplates",
1620
+ operation: "single",
1621
+ method: "previewTemplate",
1622
+ routeParams
1623
+ };
1624
+ }
1625
+ if (id && !subresource && httpMethod === "GET") {
1626
+ routeParams.templateId = id;
1627
+ return {
1628
+ service: "emailTemplates",
1629
+ operation: "single",
1630
+ method: "getTemplate",
1631
+ routeParams
1632
+ };
1633
+ }
1634
+ if (id && !subresource && httpMethod === "PATCH") {
1635
+ routeParams.templateId = id;
1636
+ return {
1637
+ service: "emailTemplates",
1638
+ operation: "update",
1639
+ method: "updateTemplate",
1640
+ routeParams
1641
+ };
1642
+ }
1643
+ if (id && !subresource && httpMethod === "DELETE") {
1644
+ routeParams.templateId = id;
1645
+ return {
1646
+ service: "emailTemplates",
1647
+ operation: "delete",
1648
+ method: "deleteTemplate",
1649
+ routeParams
1650
+ };
1651
+ }
1652
+ return null;
1653
+ }
1654
+ function parseUserFieldRoutes(id, subresource, httpMethod, routeParams) {
1655
+ if (!id && httpMethod === "GET") {
1656
+ return {
1657
+ service: "userFields",
1658
+ operation: "list",
1659
+ method: "listUserFields",
1660
+ routeParams
1661
+ };
1662
+ }
1663
+ if (!id && httpMethod === "POST") {
1664
+ return {
1665
+ service: "userFields",
1666
+ operation: "create",
1667
+ method: "createField",
1668
+ routeParams
1669
+ };
1670
+ }
1671
+ if (id === "reorder" && !subresource && httpMethod === "PATCH") {
1672
+ return {
1673
+ service: "userFields",
1674
+ operation: "update",
1675
+ method: "reorderFields",
1676
+ routeParams
1677
+ };
1678
+ }
1679
+ if (id && !subresource && httpMethod === "GET") {
1680
+ routeParams.fieldId = id;
1681
+ return {
1682
+ service: "userFields",
1683
+ operation: "single",
1684
+ method: "getField",
1685
+ routeParams
1686
+ };
1687
+ }
1688
+ if (id && !subresource && httpMethod === "PATCH") {
1689
+ routeParams.fieldId = id;
1690
+ return {
1691
+ service: "userFields",
1692
+ operation: "update",
1693
+ method: "updateField",
1694
+ routeParams
1695
+ };
1696
+ }
1697
+ if (id && !subresource && httpMethod === "DELETE") {
1698
+ routeParams.fieldId = id;
1699
+ return {
1700
+ service: "userFields",
1701
+ operation: "delete",
1702
+ method: "deleteField",
1703
+ routeParams
1704
+ };
1705
+ }
1706
+ return null;
1707
+ }
1708
+ function parseApiKeyRoutes(id, httpMethod, routeParams) {
1709
+ if (!id && httpMethod === "GET") {
1710
+ return {
1711
+ service: "apiKeys",
1712
+ operation: "list",
1713
+ method: "listApiKeys",
1714
+ routeParams
1715
+ };
1716
+ }
1717
+ if (!id && httpMethod === "POST") {
1718
+ return {
1719
+ service: "apiKeys",
1720
+ operation: "create",
1721
+ method: "createApiKey",
1722
+ routeParams
1723
+ };
1724
+ }
1725
+ if (id && httpMethod === "GET") {
1726
+ routeParams.apiKeyId = id;
1727
+ return {
1728
+ service: "apiKeys",
1729
+ operation: "single",
1730
+ method: "getApiKeyById",
1731
+ routeParams
1732
+ };
1733
+ }
1734
+ if (id && httpMethod === "PATCH") {
1735
+ routeParams.apiKeyId = id;
1736
+ return {
1737
+ service: "apiKeys",
1738
+ operation: "update",
1739
+ method: "updateApiKey",
1740
+ routeParams
1741
+ };
1742
+ }
1743
+ if (id && httpMethod === "DELETE") {
1744
+ routeParams.apiKeyId = id;
1745
+ return {
1746
+ service: "apiKeys",
1747
+ operation: "delete",
1748
+ method: "revokeApiKey",
1749
+ routeParams
1750
+ };
1751
+ }
1752
+ return null;
1753
+ }
1754
+ function parseDashboardRoutes(id, httpMethod, routeParams) {
1755
+ if (httpMethod !== "GET") return null;
1756
+ if (id === "stats") {
1757
+ return {
1758
+ service: "dashboard",
1759
+ operation: "list",
1760
+ method: "getDashboardStats",
1761
+ routeParams
1762
+ };
1763
+ }
1764
+ if (id === "recent-entries") {
1765
+ return {
1766
+ service: "dashboard",
1767
+ operation: "list",
1768
+ method: "getDashboardRecentEntries",
1769
+ routeParams
1770
+ };
1771
+ }
1772
+ if (id === "activity") {
1773
+ return {
1774
+ service: "dashboard",
1775
+ operation: "list",
1776
+ method: "getDashboardActivity",
1777
+ routeParams
1778
+ };
1779
+ }
1780
+ return null;
1781
+ }
1782
+ function parseSchemaRoutes(id, httpMethod, routeParams) {
1783
+ if (httpMethod !== "GET") return null;
1784
+ if (id === "journal") {
1785
+ return {
1786
+ service: "schema",
1787
+ operation: "list",
1788
+ method: "getSchemaJournal",
1789
+ routeParams
1790
+ };
1791
+ }
1792
+ return null;
1793
+ }
1794
+ function parseEmailRoutes(id, httpMethod, routeParams) {
1795
+ if (id === "send" && httpMethod === "POST") {
1796
+ return {
1797
+ service: "email",
1798
+ operation: "create",
1799
+ method: "send",
1800
+ routeParams
1801
+ };
1802
+ }
1803
+ if (id === "send-with-template" && httpMethod === "POST") {
1804
+ return {
1805
+ service: "email",
1806
+ operation: "create",
1807
+ method: "sendWithTemplate",
1808
+ routeParams
1809
+ };
1810
+ }
1811
+ return null;
1812
+ }
1813
+ function parseRestRoute(params, httpMethod, searchParams) {
1814
+ if (params.length === 0) return {};
1815
+ const [resource, id, subresource, subId, ...additionalParams] = params;
1816
+ const routeParams = {};
1817
+ if (searchParams) {
1818
+ let hasBracketWhere = false;
1819
+ for (const [key, value] of searchParams.entries()) {
1820
+ if (key.startsWith("where[")) {
1821
+ hasBracketWhere = true;
1822
+ } else {
1823
+ routeParams[key] = value;
1824
+ }
1825
+ }
1826
+ if (hasBracketWhere && !routeParams.where) {
1827
+ const parsed = parseWhereQuery(searchParams);
1828
+ if (parsed) {
1829
+ routeParams.where = JSON.stringify(parsed);
1830
+ }
1831
+ }
1832
+ }
1833
+ if (resource === "me") {
1834
+ const result = parseMeRoutes(httpMethod, id, routeParams);
1835
+ if (result) return result;
1836
+ }
1837
+ if (resource === "users") {
1838
+ const result = parseUserRoutes(
1839
+ id,
1840
+ subresource,
1841
+ subId,
1842
+ additionalParams,
1843
+ httpMethod,
1844
+ routeParams
1845
+ );
1846
+ if (result) return result;
1847
+ }
1848
+ if (resource === "roles") {
1849
+ const result = parseRoleRoutes(
1850
+ id,
1851
+ subresource,
1852
+ subId,
1853
+ httpMethod,
1854
+ routeParams
1855
+ );
1856
+ if (result) return result;
1857
+ }
1858
+ if (resource === "collections") {
1859
+ const result = parseCollectionRoutes(
1860
+ id,
1861
+ subresource,
1862
+ subId,
1863
+ httpMethod,
1864
+ routeParams,
1865
+ additionalParams
1866
+ );
1867
+ if (result) return result;
1868
+ }
1869
+ if (resource === "permissions") {
1870
+ const result = parsePermissionRoutes(id, httpMethod, routeParams);
1871
+ if (result) return result;
1872
+ }
1873
+ if (resource === "singles") {
1874
+ const result = parseSingleRoutes(id, subresource, subId, httpMethod, routeParams);
1875
+ if (result) return result;
1876
+ }
1877
+ if (resource === "forms") {
1878
+ const result = parseFormsRoutes(id, subresource, httpMethod, routeParams);
1879
+ if (result) return result;
1880
+ }
1881
+ if (resource === "components") {
1882
+ const result = parseComponentRoutes(id, httpMethod, routeParams, subresource, subId);
1883
+ if (result) return result;
1884
+ }
1885
+ if (resource === "email") {
1886
+ const result = parseEmailRoutes(id, httpMethod, routeParams);
1887
+ if (result) return result;
1888
+ }
1889
+ if (resource === "email-providers") {
1890
+ const result = parseEmailProviderRoutes(
1891
+ id,
1892
+ subresource,
1893
+ httpMethod,
1894
+ routeParams
1895
+ );
1896
+ if (result) return result;
1897
+ }
1898
+ if (resource === "email-templates") {
1899
+ const result = parseEmailTemplateRoutes(
1900
+ id,
1901
+ subresource,
1902
+ httpMethod,
1903
+ routeParams
1904
+ );
1905
+ if (result) return result;
1906
+ }
1907
+ if (resource === "user-fields") {
1908
+ const result = parseUserFieldRoutes(
1909
+ id,
1910
+ subresource,
1911
+ httpMethod,
1912
+ routeParams
1913
+ );
1914
+ if (result) return result;
1915
+ }
1916
+ if (resource === "api-keys") {
1917
+ const result = parseApiKeyRoutes(id, httpMethod, routeParams);
1918
+ if (result) return result;
1919
+ }
1920
+ if (resource === "dashboard") {
1921
+ const result = parseDashboardRoutes(id, httpMethod, routeParams);
1922
+ if (result) return result;
1923
+ }
1924
+ if (resource === "schema") {
1925
+ const result = parseSchemaRoutes(id, httpMethod, routeParams);
1926
+ if (result) return result;
1927
+ }
1928
+ if (resource === "general-settings") {
1929
+ const method = httpMethod === "GET" ? "getGeneralSettings" : "updateGeneralSettings";
1930
+ const operation = httpMethod === "GET" ? "single" : "update";
1931
+ return { service: "generalSettings", operation, method, routeParams };
1932
+ }
1933
+ if (resource === "image-sizes") {
1934
+ if (id === "regeneration-status") {
1935
+ return {
1936
+ service: "imageSizes",
1937
+ operation: "single",
1938
+ method: "regenerationStatus",
1939
+ routeParams
1940
+ };
1941
+ }
1942
+ if (id === "regenerate") {
1943
+ return {
1944
+ service: "imageSizes",
1945
+ operation: "single",
1946
+ method: "regenerate",
1947
+ routeParams
1948
+ };
1949
+ }
1950
+ if (id) routeParams.imageId = id;
1951
+ return {
1952
+ service: "imageSizes",
1953
+ operation: "list",
1954
+ method: "imageSizes",
1955
+ routeParams
1956
+ };
1957
+ }
1958
+ return {};
1959
+ }
1960
+
1961
+ // src/domains/audit/audit-log-writer.ts
1962
+ import { randomUUID } from "crypto";
1963
+ function buildAuditLogWriter(getService2) {
1964
+ return {
1965
+ async write(event) {
1966
+ try {
1967
+ const adapter = getService2("adapter");
1968
+ const db = adapter.getDrizzle();
1969
+ const schema = getDialectTables();
1970
+ const table = schema.auditLog;
1971
+ if (!table) {
1972
+ return;
1973
+ }
1974
+ await db.insert(table).values({
1975
+ id: randomUUID(),
1976
+ kind: event.kind,
1977
+ actorUserId: event.actorUserId ?? null,
1978
+ targetUserId: event.targetUserId ?? null,
1979
+ ipAddress: event.ipAddress ?? null,
1980
+ userAgent: event.userAgent ?? null,
1981
+ metadata: event.metadata ?? null,
1982
+ createdAt: /* @__PURE__ */ new Date()
1983
+ });
1984
+ } catch (err) {
1985
+ getNextlyLogger().warn({
1986
+ kind: "audit-log-write-failed",
1987
+ eventKind: event.kind,
1988
+ error: err instanceof Error ? err.message : String(err)
1989
+ });
1990
+ }
1991
+ }
1992
+ };
1993
+ }
1994
+
1995
+ // src/auth/handlers/deps-bridge.ts
1996
+ function buildAuthRouterDeps(getService2) {
1997
+ return {
1998
+ secret: env.NEXTLY_SECRET || "",
1999
+ isProduction: env.NODE_ENV === "production",
2000
+ accessTokenTTL: 900,
2001
+ // 15 minutes
2002
+ refreshTokenTTL: 7 * 24 * 60 * 60,
2003
+ // 7 days
2004
+ maxLoginAttempts: 5,
2005
+ lockoutDurationSeconds: 15 * 60,
2006
+ // 15 minutes
2007
+ loginStallTimeMs: 500,
2008
+ requireEmailVerification: true,
2009
+ // Spec §13.2: read the host-app's auth.revealRegistrationConflict flag
2010
+ // from the registered NextlyConfig. Defaults to false (silent-success on
2011
+ // email conflict) when config is not yet initialised or the flag is
2012
+ // unset. The schema is already populated by sanitizeConfig.
2013
+ revealRegistrationConflict: readRevealRegistrationConflict(getService2),
2014
+ devAutoLogin: readDevAutoLogin(getService2),
2015
+ allowedOrigins: env.NEXTLY_ALLOWED_ORIGINS_PARSED || [],
2016
+ trustProxy: readTrustProxy(getService2),
2017
+ trustedProxyIps: parseTrustedProxyIpsEnv(process.env.TRUSTED_PROXY_IPS),
2018
+ authRateLimit: readAuthRateLimit(getService2),
2019
+ auditLog: buildAuditLogWriter(getService2),
2020
+ findUserByEmail: async (email) => {
2021
+ try {
2022
+ const adapter = getService2("adapter");
2023
+ const db = adapter.getDrizzle();
2024
+ const schema = getDialectTables();
2025
+ const { eq } = await import("drizzle-orm");
2026
+ const result = await db.select().from(schema.users).where(eq(schema.users.email, email.trim().toLowerCase())).limit(1);
2027
+ return result[0] || null;
2028
+ } catch {
2029
+ return null;
2030
+ }
2031
+ },
2032
+ findUserById: async (userId) => {
2033
+ try {
2034
+ const adapter = getService2("adapter");
2035
+ const db = adapter.getDrizzle();
2036
+ const schema = getDialectTables();
2037
+ const { eq } = await import("drizzle-orm");
2038
+ const result = await db.select().from(schema.users).where(eq(schema.users.id, userId)).limit(1);
2039
+ return result[0] || null;
2040
+ } catch {
2041
+ return null;
2042
+ }
2043
+ },
2044
+ incrementFailedAttempts: async (userId) => {
2045
+ const adapter = getService2("adapter");
2046
+ const db = adapter.getDrizzle();
2047
+ const schema = getDialectTables();
2048
+ const { eq, sql: sql2 } = await import("drizzle-orm");
2049
+ await db.update(schema.users).set({
2050
+ failedLoginAttempts: sql2`${schema.users.failedLoginAttempts} + 1`
2051
+ }).where(eq(schema.users.id, userId));
2052
+ },
2053
+ lockAccount: async (userId, lockedUntil) => {
2054
+ const adapter = getService2("adapter");
2055
+ const db = adapter.getDrizzle();
2056
+ const schema = getDialectTables();
2057
+ const { eq } = await import("drizzle-orm");
2058
+ await db.update(schema.users).set({ lockedUntil, failedLoginAttempts: 0 }).where(eq(schema.users.id, userId));
2059
+ },
2060
+ resetFailedAttempts: async (userId) => {
2061
+ const adapter = getService2("adapter");
2062
+ const db = adapter.getDrizzle();
2063
+ const schema = getDialectTables();
2064
+ const { eq } = await import("drizzle-orm");
2065
+ await db.update(schema.users).set({ failedLoginAttempts: 0, lockedUntil: null }).where(eq(schema.users.id, userId));
2066
+ },
2067
+ fetchRoleIds: async (userId) => {
2068
+ try {
2069
+ const adapter = getService2("adapter");
2070
+ const db = adapter.getDrizzle();
2071
+ const schema = getDialectTables();
2072
+ const { eq, isNull, or, gt: gt2 } = await import("drizzle-orm");
2073
+ const rows = await db.select({ roleId: schema.userRoles.roleId }).from(schema.userRoles).where(
2074
+ eq(schema.userRoles.userId, userId),
2075
+ // Only non-expired roles
2076
+ or(
2077
+ isNull(schema.userRoles.expiresAt),
2078
+ gt2(schema.userRoles.expiresAt, /* @__PURE__ */ new Date())
2079
+ )
2080
+ );
2081
+ return rows.map((r) => r.roleId);
2082
+ } catch {
2083
+ return [];
2084
+ }
2085
+ },
2086
+ fetchCustomFields: async (userId) => {
2087
+ try {
2088
+ const { container: container2 } = await import("./container-ORGFGYSZ.mjs");
2089
+ if (!container2.has("config") || !container2.has("userExtSchemaService")) {
2090
+ return {};
2091
+ }
2092
+ const config = container2.get("config");
2093
+ const userFields = config?.users?.fields;
2094
+ if (!userFields?.length) return {};
2095
+ const userExtSchemaService = getService2("userExtSchemaService");
2096
+ if (!userExtSchemaService?.hasMergedFields()) return {};
2097
+ const extTable = userExtSchemaService.generateRuntimeSchema(userFields);
2098
+ const { eq } = await import("drizzle-orm");
2099
+ const adapter = getService2("adapter");
2100
+ const db = adapter.getDrizzle();
2101
+ const rows = await db.select().from(extTable).where(eq(extTable.user_id, userId)).limit(1);
2102
+ if (!rows[0]) return {};
2103
+ const { id: _id, user_id: _uid, ...customFields } = rows[0];
2104
+ return customFields;
2105
+ } catch {
2106
+ return {};
2107
+ }
2108
+ },
2109
+ storeRefreshToken: async (record) => {
2110
+ const adapter = getService2("adapter");
2111
+ const db = adapter.getDrizzle();
2112
+ const schema = getDialectTables();
2113
+ await db.insert(schema.refreshTokens).values(record);
2114
+ },
2115
+ findRefreshTokenByHash: async (tokenHash) => {
2116
+ const adapter = getService2("adapter");
2117
+ const db = adapter.getDrizzle();
2118
+ const schema = getDialectTables();
2119
+ const { eq } = await import("drizzle-orm");
2120
+ const rows = await db.select().from(schema.refreshTokens).where(eq(schema.refreshTokens.tokenHash, tokenHash)).limit(1);
2121
+ return rows[0] || null;
2122
+ },
2123
+ deleteRefreshToken: async (id) => {
2124
+ const adapter = getService2("adapter");
2125
+ const db = adapter.getDrizzle();
2126
+ const schema = getDialectTables();
2127
+ const { eq } = await import("drizzle-orm");
2128
+ await db.delete(schema.refreshTokens).where(eq(schema.refreshTokens.id, id));
2129
+ },
2130
+ deleteRefreshTokenByHash: async (tokenHash) => {
2131
+ const adapter = getService2("adapter");
2132
+ const db = adapter.getDrizzle();
2133
+ const schema = getDialectTables();
2134
+ const { eq } = await import("drizzle-orm");
2135
+ await db.delete(schema.refreshTokens).where(eq(schema.refreshTokens.tokenHash, tokenHash));
2136
+ },
2137
+ deleteAllRefreshTokensForUser: async (userId) => {
2138
+ const adapter = getService2("adapter");
2139
+ const db = adapter.getDrizzle();
2140
+ const schema = getDialectTables();
2141
+ const { eq } = await import("drizzle-orm");
2142
+ await db.delete(schema.refreshTokens).where(eq(schema.refreshTokens.userId, userId));
2143
+ },
2144
+ getUserCount: async () => {
2145
+ try {
2146
+ const adapter = getService2("adapter");
2147
+ const db = adapter.getDrizzle();
2148
+ const schema = getDialectTables();
2149
+ const { count } = await import("drizzle-orm");
2150
+ const result = await db.select({ count: count() }).from(schema.users);
2151
+ return Number(result[0]?.count || 0);
2152
+ } catch {
2153
+ return 0;
2154
+ }
2155
+ },
2156
+ createSuperAdmin: async (data) => {
2157
+ const { seedPermissions } = await import("./permissions-3DZZQZMI.mjs");
2158
+ const { seedSuperAdmin } = await import("./super-admin-G5ZK5F4T.mjs");
2159
+ const adapter = getService2("adapter");
2160
+ await seedPermissions(adapter, { silent: true });
2161
+ const result = await seedSuperAdmin(adapter, {
2162
+ email: data.email,
2163
+ password: data.password,
2164
+ name: data.name,
2165
+ silent: true
2166
+ });
2167
+ if (!result.success) {
2168
+ throw new Error(
2169
+ result.errorMessages?.[0] || "Failed to create admin account"
2170
+ );
2171
+ }
2172
+ const db = adapter.getDrizzle();
2173
+ const schema = getDialectTables();
2174
+ const { eq } = await import("drizzle-orm");
2175
+ const users = await db.select({ id: schema.users.id }).from(schema.users).where(eq(schema.users.email, data.email.trim().toLowerCase())).limit(1);
2176
+ return {
2177
+ id: users[0]?.id || "",
2178
+ email: data.email,
2179
+ name: data.name
2180
+ };
2181
+ },
2182
+ seedPermissions: async () => {
2183
+ const { seedPermissions } = await import("./permissions-3DZZQZMI.mjs");
2184
+ const adapter = getService2("adapter");
2185
+ await seedPermissions(adapter, { silent: true });
2186
+ },
2187
+ registerUser: async (data) => {
2188
+ const authService = getService2("authService");
2189
+ const user = await authService.registerUser(data);
2190
+ return { id: user.id, email: user.email, name: user.name };
2191
+ },
2192
+ generatePasswordResetToken: async (email, redirectPath) => {
2193
+ const authService = getService2("authService");
2194
+ const result = await authService.generatePasswordResetToken(email, {
2195
+ redirectPath
2196
+ });
2197
+ return { token: result.token };
2198
+ },
2199
+ resetPasswordWithToken: async (token, newPassword) => {
2200
+ const authService = getService2("authService");
2201
+ const result = await authService.resetPasswordWithToken(
2202
+ token,
2203
+ newPassword
2204
+ );
2205
+ return { email: result.email };
2206
+ },
2207
+ changePassword: async (userId, currentPassword, newPassword) => {
2208
+ const authService = getService2("authService");
2209
+ try {
2210
+ await authService.changePassword(userId, currentPassword, newPassword);
2211
+ return { success: true };
2212
+ } catch (err) {
2213
+ return {
2214
+ success: false,
2215
+ error: NextlyError.is(err) ? err.publicMessage : "Failed to change password"
2216
+ };
2217
+ }
2218
+ },
2219
+ verifyEmail: async (token) => {
2220
+ const authService = getService2("authService");
2221
+ try {
2222
+ const result = await authService.verifyEmail(token);
2223
+ return {
2224
+ success: true,
2225
+ email: result.email
2226
+ };
2227
+ } catch (err) {
2228
+ return {
2229
+ success: false,
2230
+ error: NextlyError.is(err) ? err.publicMessage : "Failed to verify email"
2231
+ };
2232
+ }
2233
+ },
2234
+ resendVerificationEmail: async (email) => {
2235
+ try {
2236
+ const authService = getService2("authService");
2237
+ await authService.generateEmailVerificationToken(email);
2238
+ return { success: true };
2239
+ } catch {
2240
+ return { success: true };
2241
+ }
2242
+ }
2243
+ };
2244
+ }
2245
+ function readRevealRegistrationConflict(getService2) {
2246
+ try {
2247
+ const config = getService2("config");
2248
+ if (config && typeof config === "object" && "auth" in config) {
2249
+ const auth = config.auth;
2250
+ if (auth && typeof auth === "object" && "revealRegistrationConflict" in auth) {
2251
+ return auth.revealRegistrationConflict === true;
2252
+ }
2253
+ }
2254
+ return false;
2255
+ } catch {
2256
+ return false;
2257
+ }
2258
+ }
2259
+ function readDevAutoLogin(getService2) {
2260
+ try {
2261
+ const config = getService2("config");
2262
+ if (config && typeof config === "object" && "admin" in config) {
2263
+ const admin = config.admin;
2264
+ if (admin && typeof admin === "object" && "devAutoLogin" in admin) {
2265
+ const dal = admin.devAutoLogin;
2266
+ if (dal && typeof dal === "object" && "email" in dal && typeof dal.email === "string") {
2267
+ const typed = dal;
2268
+ return {
2269
+ email: typed.email,
2270
+ password: typed.password
2271
+ };
2272
+ }
2273
+ }
2274
+ }
2275
+ return false;
2276
+ } catch {
2277
+ return false;
2278
+ }
2279
+ }
2280
+ function readTrustProxy(getService2) {
2281
+ try {
2282
+ const config = getService2("config");
2283
+ if (config && typeof config === "object" && "security" in config) {
2284
+ const security = config.security;
2285
+ if (security && typeof security === "object" && "trustProxy" in security) {
2286
+ return security.trustProxy === true;
2287
+ }
2288
+ }
2289
+ return false;
2290
+ } catch {
2291
+ return false;
2292
+ }
2293
+ }
2294
+ function readAuthRateLimit(getService2) {
2295
+ const fallback = { requestsPerHour: 30, windowMs: 36e5 };
2296
+ try {
2297
+ const config = getService2("config");
2298
+ if (config && typeof config === "object" && "security" in config) {
2299
+ const security = config.security;
2300
+ if (security && typeof security === "object" && "authRateLimit" in security) {
2301
+ const arl = security.authRateLimit;
2302
+ return {
2303
+ requestsPerHour: typeof arl?.requestsPerHour === "number" ? arl.requestsPerHour : fallback.requestsPerHour,
2304
+ windowMs: typeof arl?.windowMs === "number" ? arl.windowMs : fallback.windowMs
2305
+ };
2306
+ }
2307
+ }
2308
+ return fallback;
2309
+ } catch {
2310
+ return fallback;
2311
+ }
2312
+ }
2313
+
2314
+ // src/route-handler/auth-handler.ts
2315
+ var _dispatcher = null;
2316
+ var _storedConfig = null;
2317
+ function setHandlerConfig(config) {
2318
+ _storedConfig = config;
2319
+ }
2320
+ function getHandlerConfig() {
2321
+ return _storedConfig;
2322
+ }
2323
+ async function ensureServicesInitialized() {
2324
+ if (!isServicesRegistered()) {
2325
+ const nextlyConfig = _storedConfig;
2326
+ const serviceConfig = {
2327
+ imageProcessor: getImageProcessor()
2328
+ };
2329
+ if (nextlyConfig) {
2330
+ if (nextlyConfig.plugins) serviceConfig.plugins = nextlyConfig.plugins;
2331
+ if (nextlyConfig.collections)
2332
+ serviceConfig.collections = nextlyConfig.collections;
2333
+ if (nextlyConfig.storage)
2334
+ serviceConfig.storagePlugins = nextlyConfig.storage;
2335
+ if (nextlyConfig.email) serviceConfig.email = nextlyConfig.email;
2336
+ if (nextlyConfig.users) serviceConfig.users = nextlyConfig.users;
2337
+ if (nextlyConfig.admin) serviceConfig.admin = nextlyConfig.admin;
2338
+ if (nextlyConfig.auth) serviceConfig.auth = nextlyConfig.auth;
2339
+ if (nextlyConfig.security)
2340
+ serviceConfig.security = nextlyConfig.security;
2341
+ if (nextlyConfig.apiKeys)
2342
+ serviceConfig.apiKeys = nextlyConfig.apiKeys;
2343
+ if (nextlyConfig.db) {
2344
+ const dbConfig = nextlyConfig.db;
2345
+ if (dbConfig.schemasDir) serviceConfig.schemasDir = dbConfig.schemasDir;
2346
+ if (dbConfig.migrationsDir)
2347
+ serviceConfig.migrationsDir = dbConfig.migrationsDir;
2348
+ }
2349
+ }
2350
+ await registerServices(serviceConfig);
2351
+ try {
2352
+ const emailTemplateService = getService("emailTemplateService");
2353
+ await emailTemplateService.ensureBuiltInTemplates();
2354
+ } catch {
2355
+ }
2356
+ try {
2357
+ const permissionSeedService = getService("permissionSeedService");
2358
+ const systemResult = await permissionSeedService.seedSystemPermissions();
2359
+ const collectionResult = await permissionSeedService.seedAllCollectionPermissions();
2360
+ const singleResult = await permissionSeedService.seedAllSinglePermissions();
2361
+ const allNewIds = [
2362
+ ...systemResult.newPermissionIds,
2363
+ ...collectionResult.newPermissionIds,
2364
+ ...singleResult.newPermissionIds
2365
+ ];
2366
+ if (allNewIds.length > 0) {
2367
+ await permissionSeedService.assignNewPermissionsToSuperAdmin(allNewIds);
2368
+ }
2369
+ } catch {
2370
+ }
2371
+ try {
2372
+ const userExtSchemaService = getService("userExtSchemaService");
2373
+ await userExtSchemaService.loadMergedFields();
2374
+ if (userExtSchemaService.hasMergedFields()) {
2375
+ const adapter = getService("adapter");
2376
+ const drizzleDb = adapter.getDrizzle();
2377
+ await userExtSchemaService.ensureUserExtSchema(drizzleDb);
2378
+ }
2379
+ } catch (err) {
2380
+ console.error(
2381
+ "[Auth Handler] Error during user_ext schema setup:",
2382
+ err instanceof Error ? err.message : String(err)
2383
+ );
2384
+ }
2385
+ if (nextlyConfig) {
2386
+ const pluginCount = Array.isArray(nextlyConfig.plugins) ? nextlyConfig.plugins.length : 0;
2387
+ const collectionCount = Array.isArray(nextlyConfig.collections) ? nextlyConfig.collections.length : 0;
2388
+ const storageCount = Array.isArray(nextlyConfig.storage) ? nextlyConfig.storage.length : 0;
2389
+ console.log(
2390
+ `[Auth Handler] Services auto-initialized with config (${pluginCount} plugin(s), ${collectionCount} collection(s), ${storageCount} storage adapter(s))`
2391
+ );
2392
+ } else {
2393
+ console.log("[Auth Handler] Services auto-initialized with defaults");
2394
+ }
2395
+ const { runBootTimeApplyIfDev } = await import("./boot-apply-PQSYLDIN.mjs");
2396
+ await runBootTimeApplyIfDev({ caller: "auth-handler" });
2397
+ ensureHmrListener();
2398
+ }
2399
+ }
2400
+ async function getDispatcherInstance() {
2401
+ await ensureServicesInitialized();
2402
+ if (!_dispatcher) {
2403
+ _dispatcher = new ServiceDispatcher();
2404
+ }
2405
+ return _dispatcher;
2406
+ }
2407
+ async function handleAuthRequest(req, params, _httpMethod) {
2408
+ await ensureServicesInitialized();
2409
+ const authPath = params.slice(1).join("/");
2410
+ const deps = buildAuthRouterDeps(getService);
2411
+ const response = await routeAuthRequest(req, authPath, deps);
2412
+ if (response) {
2413
+ return response;
2414
+ }
2415
+ return new Response(
2416
+ JSON.stringify({
2417
+ error: { code: "NOT_FOUND", message: "Auth endpoint not found" }
2418
+ }),
2419
+ { status: 404, headers: { "Content-Type": "application/json" } }
2420
+ );
2421
+ }
2422
+ async function getDispatcher() {
2423
+ return getDispatcherInstance();
2424
+ }
2425
+
2426
+ // src/routeHandler.ts
2427
+ var globalSchemaVersion = 0;
2428
+ function bumpSchemaVersion() {
2429
+ globalSchemaVersion++;
2430
+ return globalSchemaVersion;
2431
+ }
2432
+ function getSchemaVersionHeader() {
2433
+ return globalSchemaVersion;
2434
+ }
2435
+ async function applyGlobalDateFormatting(response, req) {
2436
+ const contentType = response.headers.get("content-type") || "";
2437
+ if (!contentType.toLowerCase().includes("application/json")) {
2438
+ return response;
2439
+ }
2440
+ if (req) {
2441
+ const url = new URL(req.url);
2442
+ if (url.pathname.includes("/auth/")) {
2443
+ return response;
2444
+ }
2445
+ }
2446
+ return withTimezoneFormatting(response);
2447
+ }
2448
+ async function guardSuperAdminRoleAssignment(requestingUserId, method, body) {
2449
+ let roleIdsToCheck = [];
2450
+ if (method === "createLocalUser" || method === "updateUser") {
2451
+ const b = body;
2452
+ if (Array.isArray(b?.roles) && b.roles.length > 0) {
2453
+ roleIdsToCheck = b.roles;
2454
+ }
2455
+ } else if (method === "assignRoleToUser") {
2456
+ const b = body;
2457
+ const roleId = b?.roleId;
2458
+ if (roleId) roleIdsToCheck = [roleId];
2459
+ }
2460
+ if (roleIdsToCheck.length === 0) return null;
2461
+ const hasSuperAdmin = await containsSuperAdminRole(roleIdsToCheck);
2462
+ if (!hasSuperAdmin) return null;
2463
+ const callerIsSuperAdmin = await isSuperAdmin(requestingUserId);
2464
+ if (callerIsSuperAdmin) return null;
2465
+ return new Response(
2466
+ JSON.stringify({
2467
+ error: "Only super-admins can assign the super_admin role"
2468
+ }),
2469
+ { status: 403, headers: { "Content-Type": "application/json" } }
2470
+ );
2471
+ }
2472
+ async function guardLastSuperAdminRemoval(targetUserId, method, body) {
2473
+ if (method !== "updateUser") return null;
2474
+ const b = body;
2475
+ if (!Array.isArray(b?.roles)) return null;
2476
+ const newRoles = b.roles;
2477
+ const newRolesContainSuperAdmin = await containsSuperAdminRole(newRoles);
2478
+ if (newRolesContainSuperAdmin) return null;
2479
+ const targetIsSuperAdmin = await isSuperAdmin(targetUserId);
2480
+ if (!targetIsSuperAdmin) return null;
2481
+ const othersExist = await hasSuperAdminExcluding(targetUserId);
2482
+ if (othersExist) return null;
2483
+ return new Response(
2484
+ JSON.stringify({
2485
+ error: "Cannot remove the super_admin role: this user is the last super-admin. Assign the super_admin role to another user first."
2486
+ }),
2487
+ { status: 400, headers: { "Content-Type": "application/json" } }
2488
+ );
2489
+ }
2490
+ async function handleApiKeyRequest(req, method, routeParams) {
2491
+ const id = routeParams?.apiKeyId ?? "";
2492
+ switch (method) {
2493
+ case "listApiKeys":
2494
+ return listApiKeys(req);
2495
+ case "getApiKeyById":
2496
+ return getApiKeyById(req, id);
2497
+ case "createApiKey":
2498
+ return createApiKey(req);
2499
+ case "updateApiKey":
2500
+ return updateApiKey(req, id);
2501
+ case "revokeApiKey":
2502
+ return revokeApiKey(req, id);
2503
+ default:
2504
+ return new Response(
2505
+ JSON.stringify({ error: "Unknown API key operation" }),
2506
+ { status: 400, headers: { "Content-Type": "application/json" } }
2507
+ );
2508
+ }
2509
+ }
2510
+ async function handleGeneralSettingsRequest(req, httpMethod) {
2511
+ switch (httpMethod) {
2512
+ case "GET":
2513
+ return getGeneralSettings(req);
2514
+ case "PATCH": {
2515
+ return updateGeneralSettings(req);
2516
+ }
2517
+ default:
2518
+ return new Response(JSON.stringify({ error: "Method not allowed" }), {
2519
+ status: 405,
2520
+ headers: { "Content-Type": "application/json" }
2521
+ });
2522
+ }
2523
+ }
2524
+ async function handleImageSizesRequest(req, httpMethod, imageId) {
2525
+ switch (httpMethod) {
2526
+ case "GET":
2527
+ return imageId ? getImageSizeById(req, imageId) : listImageSizes(req);
2528
+ case "POST":
2529
+ return createImageSize(req);
2530
+ case "PATCH":
2531
+ if (!imageId)
2532
+ return new Response(JSON.stringify({ error: "ID required" }), {
2533
+ status: 400
2534
+ });
2535
+ return updateImageSize(req, imageId);
2536
+ case "DELETE":
2537
+ if (!imageId)
2538
+ return new Response(JSON.stringify({ error: "ID required" }), {
2539
+ status: 400
2540
+ });
2541
+ return deleteImageSize(req, imageId);
2542
+ default:
2543
+ return new Response(JSON.stringify({ error: "Method not allowed" }), {
2544
+ status: 405,
2545
+ headers: { "Content-Type": "application/json" }
2546
+ });
2547
+ }
2548
+ }
2549
+ async function handleDashboardRequest(req, method) {
2550
+ switch (method) {
2551
+ case "getDashboardStats":
2552
+ return getDashboardStats(req);
2553
+ case "getDashboardRecentEntries":
2554
+ return getDashboardRecentEntries(req);
2555
+ case "getDashboardActivity":
2556
+ return getDashboardActivity(req);
2557
+ default:
2558
+ return new Response(
2559
+ JSON.stringify({ error: "Unknown dashboard operation" }),
2560
+ { status: 400, headers: { "Content-Type": "application/json" } }
2561
+ );
2562
+ }
2563
+ }
2564
+ async function handleSchemaRequest(req, method) {
2565
+ switch (method) {
2566
+ case "getSchemaJournal":
2567
+ return getSchemaJournal(req);
2568
+ default:
2569
+ return new Response(
2570
+ JSON.stringify({ error: "Unknown schema operation" }),
2571
+ { status: 400, headers: { "Content-Type": "application/json" } }
2572
+ );
2573
+ }
2574
+ }
2575
+ async function handleEmailRequest(req, method) {
2576
+ switch (method) {
2577
+ case "send":
2578
+ return POST(req);
2579
+ case "sendWithTemplate":
2580
+ return POST2(req);
2581
+ default:
2582
+ return new Response(
2583
+ JSON.stringify({ error: "Unknown email operation" }),
2584
+ { status: 400, headers: { "Content-Type": "application/json" } }
2585
+ );
2586
+ }
2587
+ }
2588
+ var COLLECTION_ENTRY_METHODS = /* @__PURE__ */ new Set([
2589
+ "listEntries",
2590
+ "createEntry",
2591
+ "getEntry",
2592
+ "updateEntry",
2593
+ "deleteEntry",
2594
+ "bulkDeleteEntries",
2595
+ "bulkUpdateEntries",
2596
+ "bulkUpdateByQuery",
2597
+ "countEntries",
2598
+ "duplicateEntry"
2599
+ ]);
2600
+ var SINGLE_DOCUMENT_METHODS = /* @__PURE__ */ new Set([
2601
+ "getSingleDocument",
2602
+ "updateSingleDocument"
2603
+ ]);
2604
+ async function resolveAuthorization(req, service, method, operation, routeParams, httpMethod) {
2605
+ if (service === "collections") {
2606
+ if (COLLECTION_ENTRY_METHODS.has(method)) {
2607
+ const action2 = getActionFromOperation(operation);
2608
+ const slug = routeParams?.collectionName || "";
2609
+ return requireCollectionAccess(req, action2, slug);
2610
+ }
2611
+ if (method === "getCollection") {
2612
+ const slug = routeParams?.collectionName || "";
2613
+ return requireCollectionAccess(req, "read", slug);
2614
+ }
2615
+ return requirePermission(req, "manage", "settings");
2616
+ }
2617
+ if (service === "singles") {
2618
+ if (SINGLE_DOCUMENT_METHODS.has(method)) {
2619
+ const action2 = method === "getSingleDocument" ? "read" : "update";
2620
+ const slug = routeParams?.slug || "";
2621
+ return requireCollectionAccess(req, action2, slug);
2622
+ }
2623
+ if (method === "getSingleSchema") {
2624
+ const slug = routeParams?.slug || "";
2625
+ return requireCollectionAccess(req, "read", slug);
2626
+ }
2627
+ return requirePermission(req, "manage", "settings");
2628
+ }
2629
+ if (service === "emailProviders") {
2630
+ const action2 = getActionFromMethod(httpMethod);
2631
+ return requireAnyPermission(req, [
2632
+ { action: action2, resource: "email-providers" },
2633
+ { action: "manage", resource: "email-providers" }
2634
+ ]);
2635
+ }
2636
+ if (service === "emailTemplates") {
2637
+ const action2 = getActionFromMethod(httpMethod);
2638
+ return requireAnyPermission(req, [
2639
+ { action: action2, resource: "email-templates" },
2640
+ { action: "manage", resource: "email-templates" }
2641
+ ]);
2642
+ }
2643
+ if (service === "userFields") {
2644
+ const action2 = getActionFromMethod(httpMethod);
2645
+ return requireAnyPermission(req, [
2646
+ { action: action2, resource: "settings" },
2647
+ { action: "manage", resource: "settings" }
2648
+ ]);
2649
+ }
2650
+ if (service === "components") {
2651
+ const action2 = getActionFromMethod(httpMethod);
2652
+ return requireAnyPermission(req, [
2653
+ { action: action2, resource: "settings" },
2654
+ { action: "manage", resource: "settings" }
2655
+ ]);
2656
+ }
2657
+ if (service === "rbac") {
2658
+ if (method === "listRolePermissions") {
2659
+ return requireAnyPermission(req, [
2660
+ { action: "read", resource: "roles" },
2661
+ { action: "read", resource: "permissions" }
2662
+ ]);
2663
+ }
2664
+ if (method === "listPermissions") {
2665
+ return requireAnyPermission(req, [{ action: "read", resource: "roles" }]);
2666
+ }
2667
+ if (method === "addPermissionToRole" || method === "removePermissionFromRole") {
2668
+ return requirePermission(req, "update", "roles");
2669
+ }
2670
+ if (method === "addRoleInheritance" || method === "removeRoleInheritance") {
2671
+ return requirePermission(req, "update", "roles");
2672
+ }
2673
+ if (method === "assignRoleToUser" || method === "unassignRoleFromUser") {
2674
+ return requirePermission(req, "update", "users");
2675
+ }
2676
+ if (method === "getPermissionById") {
2677
+ return requireAnyPermission(req, [
2678
+ { action: "read", resource: "roles" },
2679
+ { action: "read", resource: "permissions" }
2680
+ ]);
2681
+ }
2682
+ if (method === "ensurePermission" || method === "updatePermission" || method === "deletePermissionById") {
2683
+ const action3 = getActionFromMethod(httpMethod);
2684
+ return requireAnyPermission(req, [
2685
+ { action: action3, resource: "permissions" },
2686
+ { action: "manage", resource: "permissions" }
2687
+ ]);
2688
+ }
2689
+ const action2 = getActionFromMethod(httpMethod);
2690
+ return requirePermission(req, action2, "roles");
2691
+ }
2692
+ const action = getActionFromMethod(httpMethod);
2693
+ return requirePermission(req, action, service);
2694
+ }
2695
+ async function handleServiceRequest(req, params, httpMethod) {
2696
+ const url = new URL(req.url);
2697
+ const searchParams = url.searchParams;
2698
+ const { service, operation, method, routeParams } = parseRestRoute(
2699
+ params,
2700
+ httpMethod,
2701
+ searchParams
2702
+ );
2703
+ if (!service || !operation || !method) {
2704
+ return new Response(
2705
+ JSON.stringify({
2706
+ error: "Invalid REST route format. Check supported endpoints: /api/users, /api/roles, /api/permissions"
2707
+ }),
2708
+ {
2709
+ status: 400,
2710
+ headers: { "Content-Type": "application/json" }
2711
+ }
2712
+ );
2713
+ }
2714
+ if (service === "apiKeys") {
2715
+ return handleApiKeyRequest(req, method, routeParams);
2716
+ }
2717
+ if (service === "generalSettings") {
2718
+ return handleGeneralSettingsRequest(req, httpMethod);
2719
+ }
2720
+ if (service === "imageSizes") {
2721
+ if (method === "regenerationStatus" || method === "regenerate") {
2722
+ return Response.json(
2723
+ {
2724
+ data: {
2725
+ pending: 0,
2726
+ total: 0,
2727
+ inProgress: false,
2728
+ message: "Batch regeneration coming soon"
2729
+ }
2730
+ },
2731
+ { status: 200 }
2732
+ );
2733
+ }
2734
+ const imageId = routeParams?.imageId;
2735
+ return handleImageSizesRequest(req, httpMethod, imageId);
2736
+ }
2737
+ if (service === "dashboard") {
2738
+ return handleDashboardRequest(req, method);
2739
+ }
2740
+ if (service === "schema") {
2741
+ return handleSchemaRequest(req, method);
2742
+ }
2743
+ if (service === "email") {
2744
+ return handleEmailRequest(req, method);
2745
+ }
2746
+ const isPublic = isPublicEndpoint(service, method);
2747
+ let authorizedUser;
2748
+ if (!isPublic) {
2749
+ if (params[0] === "me") {
2750
+ const authResult = await requireAuthentication(req);
2751
+ if (isErrorResponse(authResult)) {
2752
+ return createJsonErrorResponse(authResult);
2753
+ }
2754
+ if (routeParams) {
2755
+ routeParams.userId = authResult.userId;
2756
+ }
2757
+ authorizedUser = authResult;
2758
+ } else if (requiresAuthOnly(service, method)) {
2759
+ const authResult = await requireAuthentication(req);
2760
+ if (isErrorResponse(authResult)) {
2761
+ return createJsonErrorResponse(authResult);
2762
+ }
2763
+ authorizedUser = authResult;
2764
+ } else {
2765
+ const authResult = await resolveAuthorization(
2766
+ req,
2767
+ service,
2768
+ method,
2769
+ operation,
2770
+ routeParams,
2771
+ httpMethod
2772
+ );
2773
+ if (isErrorResponse(authResult)) {
2774
+ return createJsonErrorResponse(authResult);
2775
+ }
2776
+ authorizedUser = authResult;
2777
+ }
2778
+ }
2779
+ let body = void 0;
2780
+ if (httpMethod === "POST" || httpMethod === "PUT" || httpMethod === "PATCH") {
2781
+ try {
2782
+ const text = await req.text();
2783
+ if (text) {
2784
+ body = JSON.parse(text);
2785
+ }
2786
+ } catch {
2787
+ return new Response(
2788
+ JSON.stringify({ error: "Invalid JSON in request body" }),
2789
+ {
2790
+ status: 400,
2791
+ headers: { "Content-Type": "application/json" }
2792
+ }
2793
+ );
2794
+ }
2795
+ }
2796
+ if (authorizedUser) {
2797
+ const guardResult = await guardSuperAdminRoleAssignment(
2798
+ authorizedUser.userId,
2799
+ method,
2800
+ body
2801
+ );
2802
+ if (guardResult) return guardResult;
2803
+ const targetUserId = routeParams?.userId;
2804
+ if (targetUserId) {
2805
+ const lastSuperAdminGuard = await guardLastSuperAdminRemoval(
2806
+ targetUserId,
2807
+ method,
2808
+ body
2809
+ );
2810
+ if (lastSuperAdminGuard) return lastSuperAdminGuard;
2811
+ }
2812
+ }
2813
+ if (authorizedUser && routeParams) {
2814
+ routeParams._authenticatedUserId = authorizedUser.userId;
2815
+ if (authorizedUser.userName)
2816
+ routeParams._authenticatedUserName = authorizedUser.userName;
2817
+ if (authorizedUser.userEmail)
2818
+ routeParams._authenticatedUserEmail = authorizedUser.userEmail;
2819
+ }
2820
+ const dispatchRequest = {
2821
+ service,
2822
+ operation,
2823
+ method,
2824
+ params: routeParams,
2825
+ body,
2826
+ userId: authorizedUser?.userId,
2827
+ request: req
2828
+ // Pass request for accessing headers (IP, user-agent, etc.)
2829
+ };
2830
+ const dispatcher = await getDispatcher();
2831
+ const result = await dispatcher.dispatch(dispatchRequest);
2832
+ if (result.status === 204 || result.status === 205 || result.status === 304) {
2833
+ return new Response(null, { status: result.status });
2834
+ }
2835
+ const headers = {
2836
+ "Content-Type": "application/json"
2837
+ };
2838
+ const schemaVersion = getSchemaVersionHeader();
2839
+ if (schemaVersion !== void 0) {
2840
+ headers["X-Nextly-Schema-Version"] = String(schemaVersion);
2841
+ }
2842
+ if (!result.success) {
2843
+ const requestId = readOrGenerateRequestId(req);
2844
+ const nextlyErr = NextlyError.is(result.error) ? result.error : NextlyError.internal();
2845
+ const benignCodes = /* @__PURE__ */ new Set([
2846
+ "NOT_FOUND",
2847
+ "RATE_LIMITED",
2848
+ "AUTH_REQUIRED"
2849
+ ]);
2850
+ if (!benignCodes.has(String(nextlyErr.code))) {
2851
+ try {
2852
+ const { getNextlyLogger: getNextlyLogger2 } = await import("./logger-YE4TC7ZN.mjs");
2853
+ getNextlyLogger2().error({
2854
+ kind: "dispatcher-error",
2855
+ ...nextlyErr.toLogJSON(requestId),
2856
+ route: new URL(req.url).pathname,
2857
+ method: req.method,
2858
+ service: dispatchRequest.service,
2859
+ operation: dispatchRequest.operation,
2860
+ dispatchMethod: dispatchRequest.method
2861
+ });
2862
+ } catch {
2863
+ }
2864
+ }
2865
+ const errorHeaders = {
2866
+ "content-type": "application/problem+json",
2867
+ "x-request-id": requestId
2868
+ };
2869
+ if (schemaVersion !== void 0) {
2870
+ errorHeaders["X-Nextly-Schema-Version"] = String(schemaVersion);
2871
+ }
2872
+ if (nextlyErr.code === "RATE_LIMITED") {
2873
+ const data = nextlyErr.publicData;
2874
+ if (data && typeof data === "object" && "retryAfterSeconds" in data && typeof data.retryAfterSeconds === "number") {
2875
+ errorHeaders["retry-after"] = String(
2876
+ data.retryAfterSeconds
2877
+ );
2878
+ }
2879
+ }
2880
+ return new Response(
2881
+ JSON.stringify({ error: nextlyErr.toResponseJSON(requestId) }),
2882
+ {
2883
+ status: nextlyErr.statusCode,
2884
+ headers: errorHeaders
2885
+ }
2886
+ );
2887
+ }
2888
+ if (result.data instanceof Response) {
2889
+ const response = result.data;
2890
+ if (schemaVersion !== void 0) {
2891
+ response.headers.set("X-Nextly-Schema-Version", String(schemaVersion));
2892
+ }
2893
+ return response;
2894
+ }
2895
+ const successBody = { data: result.data };
2896
+ if (result.meta !== void 0) {
2897
+ successBody.meta = result.meta;
2898
+ }
2899
+ return new Response(JSON.stringify(successBody), {
2900
+ status: result.status,
2901
+ headers
2902
+ });
2903
+ }
2904
+ async function handleAdminMetaRequest() {
2905
+ const config = getHandlerConfig();
2906
+ const branding = config?.admin?.branding;
2907
+ const payload = {};
2908
+ if (branding?.logoUrl) payload.logoUrl = branding.logoUrl;
2909
+ if (branding?.logoUrlLight) payload.logoUrlLight = branding.logoUrlLight;
2910
+ if (branding?.logoUrlDark) payload.logoUrlDark = branding.logoUrlDark;
2911
+ if (branding?.logoText) payload.logoText = branding.logoText;
2912
+ if (branding?.favicon?.trim()) payload.favicon = branding.favicon.trim();
2913
+ const resolvedShowBuilder = typeof branding?.showBuilder === "boolean" ? branding.showBuilder : process.env.NODE_ENV !== "production";
2914
+ payload.showBuilder = resolvedShowBuilder;
2915
+ const colors = branding?.colors;
2916
+ if (colors) {
2917
+ const resolved = {};
2918
+ if (colors.primary && isValidHex(colors.primary)) {
2919
+ resolved.primary = hexToHslTriplet(colors.primary);
2920
+ resolved.primaryForeground = getForegroundForBackground(colors.primary);
2921
+ }
2922
+ if (colors.accent && isValidHex(colors.accent)) {
2923
+ resolved.accent = hexToHslTriplet(colors.accent);
2924
+ resolved.accentForeground = getForegroundForBackground(colors.accent);
2925
+ }
2926
+ if (Object.keys(resolved).length > 0) {
2927
+ payload.colors = resolved;
2928
+ }
2929
+ }
2930
+ const pluginOverrides = config?.admin?.pluginOverrides;
2931
+ const plugins = (config?.plugins ?? []).map((plugin) => {
2932
+ const pluginSlug = plugin.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
2933
+ const hostOverride = pluginOverrides?.[pluginSlug];
2934
+ const effectiveAppearance = hostOverride?.appearance ? { ...plugin.admin?.appearance, ...hostOverride.appearance } : plugin.admin?.appearance;
2935
+ const pluginCollections = plugin.collections ?? [];
2936
+ return {
2937
+ name: plugin.name,
2938
+ version: plugin.version,
2939
+ description: plugin.admin?.description,
2940
+ placement: hostOverride?.placement ?? plugin.admin?.placement ?? "plugins",
2941
+ order: hostOverride?.order ?? plugin.admin?.order,
2942
+ after: hostOverride?.after ?? plugin.admin?.after,
2943
+ appearance: effectiveAppearance,
2944
+ collections: pluginCollections.map((c) => c.slug)
2945
+ };
2946
+ });
2947
+ if (plugins.length > 0) {
2948
+ payload.plugins = plugins;
2949
+ }
2950
+ try {
2951
+ if (container.has("generalSettingsService")) {
2952
+ const svc = container.get(
2953
+ "generalSettingsService"
2954
+ );
2955
+ const settings = await svc.getSettings();
2956
+ if (settings.applicationName) payload.logoText = settings.applicationName;
2957
+ if (settings.logoUrl) payload.logoUrl = settings.logoUrl;
2958
+ const customGroups = svc.getCustomSidebarGroups(settings);
2959
+ console.log(
2960
+ "[ADMIN-META] customGroups from DB:",
2961
+ JSON.stringify(customGroups)
2962
+ );
2963
+ if (customGroups.length > 0) {
2964
+ payload.customGroups = customGroups;
2965
+ }
2966
+ }
2967
+ } catch (err) {
2968
+ console.error("[ADMIN-META] Error fetching settings from DB:", err);
2969
+ }
2970
+ return respondData(payload);
2971
+ }
2972
+ async function handleAdminMetaSidebarGroups(req) {
2973
+ try {
2974
+ const authResult = await requirePermission(req, "manage", "settings");
2975
+ if (isErrorResponse(authResult)) return createJsonErrorResponse(authResult);
2976
+ const text = await req.text();
2977
+ const body = text ? JSON.parse(text) : {};
2978
+ const groups = Array.isArray(body.groups) ? body.groups : [];
2979
+ const validated = [];
2980
+ for (const g of groups) {
2981
+ if (typeof g !== "object" || g === null) continue;
2982
+ const rec = g;
2983
+ if (typeof rec.slug === "string" && typeof rec.name === "string") {
2984
+ validated.push({
2985
+ slug: rec.slug,
2986
+ name: rec.name,
2987
+ ...typeof rec.icon === "string" && { icon: rec.icon }
2988
+ });
2989
+ }
2990
+ }
2991
+ if (!container.has("generalSettingsService")) {
2992
+ return new Response(
2993
+ JSON.stringify({ error: "Settings service not available" }),
2994
+ { status: 503, headers: { "Content-Type": "application/json" } }
2995
+ );
2996
+ }
2997
+ const svc = container.get("generalSettingsService");
2998
+ const updated = await svc.updateCustomSidebarGroups(validated);
2999
+ return respondMutation("Sidebar groups updated.", updated);
3000
+ } catch (error) {
3001
+ const message = error instanceof Error ? error.message : "Failed to update sidebar groups";
3002
+ return new Response(JSON.stringify({ error: message }), {
3003
+ status: 500,
3004
+ headers: { "Content-Type": "application/json" }
3005
+ });
3006
+ }
3007
+ }
3008
+ async function handleGet(req, params) {
3009
+ if (params[0] === "admin-meta") {
3010
+ return handleAdminMetaRequest();
3011
+ }
3012
+ if (params[0] === "dev-reload" && process.env.NODE_ENV === "development") {
3013
+ const { subscribeDevReload } = await import("./dev-reload-broadcaster-B73IQ53V.mjs");
3014
+ let unsub;
3015
+ const stream = new ReadableStream({
3016
+ start(ctrl) {
3017
+ unsub = subscribeDevReload(ctrl);
3018
+ ctrl.enqueue(": keepalive\n\n");
3019
+ },
3020
+ cancel() {
3021
+ unsub?.();
3022
+ }
3023
+ });
3024
+ return new Response(stream, {
3025
+ status: 200,
3026
+ headers: {
3027
+ "Content-Type": "text/event-stream",
3028
+ "Cache-Control": "no-cache, no-transform",
3029
+ Connection: "keep-alive",
3030
+ "X-Accel-Buffering": "no"
3031
+ }
3032
+ });
3033
+ }
3034
+ return handleServiceRequest(req, params, "GET");
3035
+ }
3036
+ async function handlePost(req, params) {
3037
+ return handleServiceRequest(req, params, "POST");
3038
+ }
3039
+ async function handlePut(req, params) {
3040
+ return handleServiceRequest(req, params, "PUT");
3041
+ }
3042
+ async function handlePatch(req, params) {
3043
+ if (params[0] === "admin-meta" && params[1] === "sidebar-groups") {
3044
+ return handleAdminMetaSidebarGroups(req);
3045
+ }
3046
+ return handleServiceRequest(req, params, "PATCH");
3047
+ }
3048
+ async function handleDelete(req, params) {
3049
+ return handleServiceRequest(req, params, "DELETE");
3050
+ }
3051
+ function isAuthRoute(params) {
3052
+ return params.length > 0 && params[0] === "auth";
3053
+ }
3054
+ function createDynamicHandlers(options) {
3055
+ if (options?.config) {
3056
+ setHandlerConfig(options.config);
3057
+ }
3058
+ const securityConfig = options?.config?.security;
3059
+ const applySecurityHeaders = createSecurityHeadersMiddleware(
3060
+ securityConfig?.headers
3061
+ );
3062
+ const cors = createCorsMiddleware(securityConfig?.cors);
3063
+ const rateLimitConfig = options?.config?.rateLimit;
3064
+ const trustedProxyIpsFromEnv = (process.env.TRUSTED_PROXY_IPS ?? "").split(",").map((s) => s.trim()).filter(Boolean);
3065
+ const checkRateLimit = createRateLimiter({
3066
+ enabled: true,
3067
+ ...rateLimitConfig ?? {},
3068
+ trustProxy: rateLimitConfig?.trustProxy ?? securityConfig?.trustProxy ?? false,
3069
+ trustedProxyIps: rateLimitConfig?.trustedProxyIps ?? trustedProxyIpsFromEnv
3070
+ });
3071
+ async function withSecurity(req, handler) {
3072
+ const preflightResponse = cors.handlePreflight(req);
3073
+ if (preflightResponse) {
3074
+ return applySecurityHeaders(preflightResponse);
3075
+ }
3076
+ const rateLimitResponse = await checkRateLimit(req);
3077
+ if (rateLimitResponse) {
3078
+ const corsRateLimited = cors.applyHeaders(req, rateLimitResponse);
3079
+ return applySecurityHeaders(corsRateLimited);
3080
+ }
3081
+ const response = await handler();
3082
+ const formattedResponse = await applyGlobalDateFormatting(response, req);
3083
+ const corsResponse = cors.applyHeaders(req, formattedResponse);
3084
+ return applySecurityHeaders(corsResponse);
3085
+ }
3086
+ return {
3087
+ GET: async (req, ctx) => {
3088
+ const resolvedParams = await ctx.params;
3089
+ const paramsList = resolvedParams.params || [];
3090
+ return withSecurity(req, async () => {
3091
+ if (isAuthRoute(paramsList))
3092
+ return handleAuthRequest(req, paramsList, "GET");
3093
+ return handleGet(req, paramsList);
3094
+ });
3095
+ },
3096
+ POST: async (req, ctx) => {
3097
+ const resolvedParams = await ctx.params;
3098
+ const paramsList = resolvedParams.params || [];
3099
+ return withSecurity(req, async () => {
3100
+ if (isAuthRoute(paramsList))
3101
+ return handleAuthRequest(req, paramsList, "POST");
3102
+ return handlePost(req, paramsList);
3103
+ });
3104
+ },
3105
+ PUT: async (req, ctx) => {
3106
+ const resolvedParams = await ctx.params;
3107
+ const paramsList = resolvedParams.params || [];
3108
+ return withSecurity(req, async () => {
3109
+ return handlePut(req, paramsList);
3110
+ });
3111
+ },
3112
+ PATCH: async (req, ctx) => {
3113
+ const resolvedParams = await ctx.params;
3114
+ const paramsList = resolvedParams.params || [];
3115
+ return withSecurity(req, async () => {
3116
+ if (isAuthRoute(paramsList))
3117
+ return handleAuthRequest(req, paramsList, "PATCH");
3118
+ return handlePatch(req, paramsList);
3119
+ });
3120
+ },
3121
+ DELETE: async (req, ctx) => {
3122
+ const resolvedParams = await ctx.params;
3123
+ const paramsList = resolvedParams.params || [];
3124
+ return withSecurity(req, async () => {
3125
+ return handleDelete(req, paramsList);
3126
+ });
3127
+ },
3128
+ OPTIONS: async (req) => {
3129
+ return withSecurity(req, async () => {
3130
+ return new Response(null, {
3131
+ status: 204,
3132
+ headers: { Allow: "GET, POST, PUT, PATCH, DELETE, OPTIONS" }
3133
+ });
3134
+ });
3135
+ }
3136
+ };
3137
+ }
3138
+ function getCollectionsService() {
3139
+ try {
3140
+ if (container.has("collectionService")) {
3141
+ return container.get("collectionService");
3142
+ }
3143
+ } catch {
3144
+ }
3145
+ return void 0;
3146
+ }
3147
+ function getCollectionsHandler() {
3148
+ try {
3149
+ if (container.has("collectionsHandler")) {
3150
+ return container.get("collectionsHandler");
3151
+ }
3152
+ } catch {
3153
+ }
3154
+ return void 0;
3155
+ }
3156
+ var _handleAdminMetaRequestForTest = handleAdminMetaRequest;
3157
+ var _handleAdminMetaSidebarGroupsForTest = handleAdminMetaSidebarGroups;
3158
+
3159
+ export {
3160
+ bumpSchemaVersion,
3161
+ createDynamicHandlers,
3162
+ getCollectionsService,
3163
+ getCollectionsHandler,
3164
+ _handleAdminMetaRequestForTest,
3165
+ _handleAdminMetaSidebarGroupsForTest
3166
+ };