@nexpress/core 0.1.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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +69 -0
  3. package/dist/audit-54XLVCWD.js +14 -0
  4. package/dist/audit-54XLVCWD.js.map +1 -0
  5. package/dist/auth.d.ts +640 -0
  6. package/dist/auth.js +94 -0
  7. package/dist/auth.js.map +1 -0
  8. package/dist/can-YLUHRJAB.js +19 -0
  9. package/dist/can-YLUHRJAB.js.map +1 -0
  10. package/dist/chunk-2G264RCD.js +68 -0
  11. package/dist/chunk-2G264RCD.js.map +1 -0
  12. package/dist/chunk-2YDGE7YX.js +92 -0
  13. package/dist/chunk-2YDGE7YX.js.map +1 -0
  14. package/dist/chunk-473S4TER.js +538 -0
  15. package/dist/chunk-473S4TER.js.map +1 -0
  16. package/dist/chunk-4ZLMEKFX.js +18 -0
  17. package/dist/chunk-4ZLMEKFX.js.map +1 -0
  18. package/dist/chunk-55FU6WED.js +179 -0
  19. package/dist/chunk-55FU6WED.js.map +1 -0
  20. package/dist/chunk-6YI5K2TI.js +1959 -0
  21. package/dist/chunk-6YI5K2TI.js.map +1 -0
  22. package/dist/chunk-BHK3AD3Q.js +41 -0
  23. package/dist/chunk-BHK3AD3Q.js.map +1 -0
  24. package/dist/chunk-CRUQBZUF.js +39 -0
  25. package/dist/chunk-CRUQBZUF.js.map +1 -0
  26. package/dist/chunk-CTSQ7BRI.js +175 -0
  27. package/dist/chunk-CTSQ7BRI.js.map +1 -0
  28. package/dist/chunk-DK2JBJH7.js +81 -0
  29. package/dist/chunk-DK2JBJH7.js.map +1 -0
  30. package/dist/chunk-DP2PREDU.js +597 -0
  31. package/dist/chunk-DP2PREDU.js.map +1 -0
  32. package/dist/chunk-EQ2Z3KMD.js +24 -0
  33. package/dist/chunk-EQ2Z3KMD.js.map +1 -0
  34. package/dist/chunk-FZ7O6DWI.js +305 -0
  35. package/dist/chunk-FZ7O6DWI.js.map +1 -0
  36. package/dist/chunk-ISLYFQWL.js +1270 -0
  37. package/dist/chunk-ISLYFQWL.js.map +1 -0
  38. package/dist/chunk-JJL74ZPK.js +68 -0
  39. package/dist/chunk-JJL74ZPK.js.map +1 -0
  40. package/dist/chunk-JKXAPSU4.js +24 -0
  41. package/dist/chunk-JKXAPSU4.js.map +1 -0
  42. package/dist/chunk-KU5M27ZC.js +24 -0
  43. package/dist/chunk-KU5M27ZC.js.map +1 -0
  44. package/dist/chunk-LSHHRDVR.js +34 -0
  45. package/dist/chunk-LSHHRDVR.js.map +1 -0
  46. package/dist/chunk-M43PGOQY.js +715 -0
  47. package/dist/chunk-M43PGOQY.js.map +1 -0
  48. package/dist/chunk-MEJAHXIO.js +150 -0
  49. package/dist/chunk-MEJAHXIO.js.map +1 -0
  50. package/dist/chunk-NUCGHWCF.js +101 -0
  51. package/dist/chunk-NUCGHWCF.js.map +1 -0
  52. package/dist/chunk-OK5HOCQI.js +845 -0
  53. package/dist/chunk-OK5HOCQI.js.map +1 -0
  54. package/dist/chunk-OROPGO65.js +13 -0
  55. package/dist/chunk-OROPGO65.js.map +1 -0
  56. package/dist/chunk-PPAS4SZR.js +176 -0
  57. package/dist/chunk-PPAS4SZR.js.map +1 -0
  58. package/dist/chunk-PPBWRKO2.js +171 -0
  59. package/dist/chunk-PPBWRKO2.js.map +1 -0
  60. package/dist/chunk-PZ5AY32C.js +10 -0
  61. package/dist/chunk-PZ5AY32C.js.map +1 -0
  62. package/dist/chunk-QO7LAQZH.js +321 -0
  63. package/dist/chunk-QO7LAQZH.js.map +1 -0
  64. package/dist/chunk-QVJ2HCAX.js +225 -0
  65. package/dist/chunk-QVJ2HCAX.js.map +1 -0
  66. package/dist/chunk-RIPHIRPP.js +68 -0
  67. package/dist/chunk-RIPHIRPP.js.map +1 -0
  68. package/dist/chunk-S27S42QY.js +134 -0
  69. package/dist/chunk-S27S42QY.js.map +1 -0
  70. package/dist/chunk-SBCVAC2Z.js +40 -0
  71. package/dist/chunk-SBCVAC2Z.js.map +1 -0
  72. package/dist/chunk-TFJ4MKPH.js +694 -0
  73. package/dist/chunk-TFJ4MKPH.js.map +1 -0
  74. package/dist/chunk-THX3SHYA.js +75 -0
  75. package/dist/chunk-THX3SHYA.js.map +1 -0
  76. package/dist/chunk-UGQSQO5B.js +222 -0
  77. package/dist/chunk-UGQSQO5B.js.map +1 -0
  78. package/dist/chunk-V2UNHGAP.js +26 -0
  79. package/dist/chunk-V2UNHGAP.js.map +1 -0
  80. package/dist/chunk-VGTPQXNQ.js +2790 -0
  81. package/dist/chunk-VGTPQXNQ.js.map +1 -0
  82. package/dist/chunk-VNIHXQ7W.js +194 -0
  83. package/dist/chunk-VNIHXQ7W.js.map +1 -0
  84. package/dist/chunk-WV272MPW.js +31 -0
  85. package/dist/chunk-WV272MPW.js.map +1 -0
  86. package/dist/chunk-X5KKBOUS.js +26 -0
  87. package/dist/chunk-X5KKBOUS.js.map +1 -0
  88. package/dist/chunk-XANPEOJC.js +17 -0
  89. package/dist/chunk-XANPEOJC.js.map +1 -0
  90. package/dist/chunk-XPVQIHAQ.js +83 -0
  91. package/dist/chunk-XPVQIHAQ.js.map +1 -0
  92. package/dist/chunk-ZCINJSS4.js +75 -0
  93. package/dist/chunk-ZCINJSS4.js.map +1 -0
  94. package/dist/community.d.ts +1425 -0
  95. package/dist/community.js +206 -0
  96. package/dist/community.js.map +1 -0
  97. package/dist/config-2GDU7PCK.js +32 -0
  98. package/dist/config-2GDU7PCK.js.map +1 -0
  99. package/dist/context-MNZ4QXPC.js +16 -0
  100. package/dist/context-MNZ4QXPC.js.map +1 -0
  101. package/dist/db-schema.d.ts +4 -0
  102. package/dist/db-schema.js +102 -0
  103. package/dist/db-schema.js.map +1 -0
  104. package/dist/db.d.ts +7 -0
  105. package/dist/db.js +117 -0
  106. package/dist/db.js.map +1 -0
  107. package/dist/digest-SY42GQSU.js +17 -0
  108. package/dist/digest-SY42GQSU.js.map +1 -0
  109. package/dist/errors-5OS3S2J3.js +22 -0
  110. package/dist/errors-5OS3S2J3.js.map +1 -0
  111. package/dist/host-OBOI4MJK.js +51 -0
  112. package/dist/host-OBOI4MJK.js.map +1 -0
  113. package/dist/i18n.d.ts +301 -0
  114. package/dist/i18n.js +68 -0
  115. package/dist/i18n.js.map +1 -0
  116. package/dist/index-B6-_vr_m.d.ts +590 -0
  117. package/dist/index-CY55LC0u.d.ts +4722 -0
  118. package/dist/index-CeiTvwbp.d.ts +168 -0
  119. package/dist/index-XwP1ET8b.d.ts +61 -0
  120. package/dist/index.d.ts +2037 -0
  121. package/dist/index.js +2205 -0
  122. package/dist/index.js.map +1 -0
  123. package/dist/job-log-VZXWQUDK.js +24 -0
  124. package/dist/job-log-VZXWQUDK.js.map +1 -0
  125. package/dist/jobs.d.ts +4 -0
  126. package/dist/jobs.js +76 -0
  127. package/dist/jobs.js.map +1 -0
  128. package/dist/logger-DqGaOU_j.d.ts +29 -0
  129. package/dist/logger-S7REWDNE.js +16 -0
  130. package/dist/logger-S7REWDNE.js.map +1 -0
  131. package/dist/media.d.ts +5 -0
  132. package/dist/media.js +41 -0
  133. package/dist/media.js.map +1 -0
  134. package/dist/mentions-2IHFVSHW.js +23 -0
  135. package/dist/mentions-2IHFVSHW.js.map +1 -0
  136. package/dist/mutes-EWAE5FZR.js +21 -0
  137. package/dist/mutes-EWAE5FZR.js.map +1 -0
  138. package/dist/notification-prefs-VPJDU7I6.js +21 -0
  139. package/dist/notification-prefs-VPJDU7I6.js.map +1 -0
  140. package/dist/observability.d.ts +156 -0
  141. package/dist/observability.js +32 -0
  142. package/dist/observability.js.map +1 -0
  143. package/dist/profanity-adapter-NU2JQSLX.js +12 -0
  144. package/dist/profanity-adapter-NU2JQSLX.js.map +1 -0
  145. package/dist/queue-XE5BC75T.js +14 -0
  146. package/dist/queue-XE5BC75T.js.map +1 -0
  147. package/dist/rate-limit.d.ts +99 -0
  148. package/dist/rate-limit.js +14 -0
  149. package/dist/rate-limit.js.map +1 -0
  150. package/dist/registry-XIXDEPVI.js +31 -0
  151. package/dist/registry-XIXDEPVI.js.map +1 -0
  152. package/dist/reputation-JRL2YQHM.js +11 -0
  153. package/dist/reputation-JRL2YQHM.js.map +1 -0
  154. package/dist/routes.d.ts +43 -0
  155. package/dist/routes.js +12 -0
  156. package/dist/routes.js.map +1 -0
  157. package/dist/scheduled-CIQM57HT.js +20 -0
  158. package/dist/scheduled-CIQM57HT.js.map +1 -0
  159. package/dist/seo.d.ts +410 -0
  160. package/dist/seo.js +44 -0
  161. package/dist/seo.js.map +1 -0
  162. package/dist/settings-FOBIESPB.js +17 -0
  163. package/dist/settings-FOBIESPB.js.map +1 -0
  164. package/dist/spam-adapter-XX3G737Z.js +12 -0
  165. package/dist/spam-adapter-XX3G737Z.js.map +1 -0
  166. package/dist/strings-VAE47B2C.js +29 -0
  167. package/dist/strings-VAE47B2C.js.map +1 -0
  168. package/dist/templates-IFVJMCJ6.js +12 -0
  169. package/dist/templates-IFVJMCJ6.js.map +1 -0
  170. package/dist/types-TlsbXS0T.d.ts +871 -0
  171. package/package.json +129 -0
package/dist/index.js ADDED
@@ -0,0 +1,2205 @@
1
+ import {
2
+ getPluginConfig,
3
+ getPluginConfigWithStatus,
4
+ introspectThemeSettingsSchema,
5
+ pluginConfigCacheTag,
6
+ setPluginConfig
7
+ } from "./chunk-QO7LAQZH.js";
8
+ import {
9
+ getPluginTemplatesForCollection,
10
+ registerPluginTemplates,
11
+ resetPluginTemplates
12
+ } from "./chunk-CRUQBZUF.js";
13
+ import {
14
+ verifyStartupSafety
15
+ } from "./chunk-2YDGE7YX.js";
16
+ import {
17
+ InMemoryRateLimiter,
18
+ getOptionalRateLimiter,
19
+ getRateLimiter,
20
+ setRateLimiter
21
+ } from "./chunk-2G264RCD.js";
22
+ import {
23
+ clearCustomRoutes,
24
+ getCustomRoutes,
25
+ registerCustomRoute
26
+ } from "./chunk-X5KKBOUS.js";
27
+ import {
28
+ DEFAULT_SITE_SEO_SETTINGS,
29
+ buildArticleJsonLd,
30
+ buildAtomFeed,
31
+ buildDiscussionForumPostingJsonLd,
32
+ buildPageMetadata,
33
+ buildPersonJsonLd,
34
+ buildSitemap,
35
+ buildWebSiteJsonLd,
36
+ getSiteSeoSettings,
37
+ renderAtomFeed,
38
+ renderSitemapIndexXml,
39
+ renderSitemapXml,
40
+ validateSeoSettingsPatch
41
+ } from "./chunk-DP2PREDU.js";
42
+ import {
43
+ ARGON2_OPTIONS,
44
+ authenticated,
45
+ consumeMemberEmailVerifyToken,
46
+ consumeMemberPasswordReset,
47
+ consumePasswordResetToken,
48
+ createMemberEmailVerifyToken,
49
+ createPasswordResetToken,
50
+ fromArctic,
51
+ getMemberFromTokenPayload,
52
+ getOAuthProvider,
53
+ hashPassword,
54
+ invalidateAllMemberSessions,
55
+ invalidateAllSessions,
56
+ isAdmin,
57
+ isEditorOrAbove,
58
+ isOwnerOrAdmin,
59
+ isTokenVerificationError,
60
+ issueOAuthState,
61
+ listMemberIdentities,
62
+ listOAuthProviders,
63
+ listUserIdentities,
64
+ registerOAuthProvider,
65
+ requestMemberPasswordReset,
66
+ requestPasswordReset,
67
+ resetOAuthProviders,
68
+ resolveMemberOAuthLogin,
69
+ resolveOAuthLogin,
70
+ revokeMemberIdentity,
71
+ revokeUserIdentity,
72
+ sha256,
73
+ signMemberToken,
74
+ signToken,
75
+ verifyCsrf,
76
+ verifyMemberToken,
77
+ verifyOAuthState,
78
+ verifyPassword,
79
+ verifyToken,
80
+ verifyTokenFull
81
+ } from "./chunk-OK5HOCQI.js";
82
+ import {
83
+ DEFAULT_REACTION_KINDS,
84
+ addReaction,
85
+ assertReactableExists,
86
+ countReactions,
87
+ createComment,
88
+ createTranslation,
89
+ deleteComment,
90
+ fileReport,
91
+ findTranslations,
92
+ follow,
93
+ getMemberProfile,
94
+ getMemberProfiles,
95
+ getRevision,
96
+ getSearchAdapter,
97
+ getTranslationProgress,
98
+ grantMemberRole,
99
+ hideComment,
100
+ isFollowing,
101
+ issueBan,
102
+ listBansForMember,
103
+ listComments,
104
+ listFollowing,
105
+ listMemberReactions,
106
+ listMemberRoleGrants,
107
+ listPendingMemberDocs,
108
+ listReports,
109
+ listRevisions,
110
+ principalCan,
111
+ purgeMemberContent,
112
+ reindexCollection,
113
+ removeReaction,
114
+ renderCommentMarkdown,
115
+ resetSearchAdapter,
116
+ resolveReport,
117
+ restoreComment,
118
+ restoreRevision,
119
+ revokeBan,
120
+ revokeMemberRole,
121
+ searchCollections,
122
+ setSearchAdapter,
123
+ staffDeleteComment,
124
+ staffHideComment,
125
+ staffRestoreComment,
126
+ unfollow,
127
+ unresolvedReportCount,
128
+ updateComment
129
+ } from "./chunk-6YI5K2TI.js";
130
+ import {
131
+ buildDigestEmail,
132
+ runDigestSweep
133
+ } from "./chunk-VNIHXQ7W.js";
134
+ import {
135
+ getMutedTargetIds,
136
+ isMuted,
137
+ listMutes,
138
+ muteMember,
139
+ unmuteMember
140
+ } from "./chunk-NUCGHWCF.js";
141
+ import {
142
+ getMemberNotificationPrefs,
143
+ isNotificationKindEnabled,
144
+ listNotificationKinds,
145
+ recordDigestSent,
146
+ registerNotificationKind,
147
+ setMemberNotificationPrefs
148
+ } from "./chunk-CTSQ7BRI.js";
149
+ import {
150
+ MENTION_HANDLE_RE,
151
+ assertOwnsNotification,
152
+ createNotification,
153
+ extractMentionHandles,
154
+ extractMentionHandlesFromDocData,
155
+ extractMentionHandlesFromRichText,
156
+ fanOutMentionNotifications,
157
+ listNotifications,
158
+ markAllNotificationsRead,
159
+ markNotificationsRead,
160
+ resolveMentionedMembers,
161
+ unreadNotificationCount
162
+ } from "./chunk-UGQSQO5B.js";
163
+ import {
164
+ applyReputation,
165
+ getReputationAdapter,
166
+ resetReputationAdapter,
167
+ setReputationAdapter
168
+ } from "./chunk-THX3SHYA.js";
169
+ import {
170
+ getSpamAdapter,
171
+ resetSpamAdapter,
172
+ setSpamAdapter
173
+ } from "./chunk-JKXAPSU4.js";
174
+ import {
175
+ getProfanityAdapter,
176
+ resetProfanityAdapter,
177
+ setProfanityAdapter
178
+ } from "./chunk-KU5M27ZC.js";
179
+ import {
180
+ publishScheduledDocuments
181
+ } from "./chunk-XPVQIHAQ.js";
182
+ import {
183
+ assertNotBanned,
184
+ getCommunityRole,
185
+ listCommunityRoles,
186
+ memberCan,
187
+ registerCommunityRole,
188
+ resetCommunityRoles,
189
+ withMemberWrite
190
+ } from "./chunk-55FU6WED.js";
191
+ import {
192
+ autosaveRevision,
193
+ buildSearchVector,
194
+ buildSearchVectorParts,
195
+ buildWeightedSearchVectorSql,
196
+ buildZodSchema,
197
+ checkNexpressCompat,
198
+ compareSemver,
199
+ createMemberDocument,
200
+ deleteDocument,
201
+ deleteMemberDocument,
202
+ dispatchPluginAction,
203
+ findDocuments,
204
+ getAllPluginIds,
205
+ getCollectionTabsForSlug,
206
+ getCollectionZodSchema,
207
+ getDashboardWidgetsFromPlugins,
208
+ getDocumentById,
209
+ getFrameworkVersion,
210
+ getPluginAdminExtension,
211
+ getPluginPageRoutes,
212
+ getPluginRegistration,
213
+ getPluginRoutes,
214
+ getRegisteredPluginSchedules,
215
+ invalidatePluginEnabled,
216
+ isPluginEnabled,
217
+ loadPlugins,
218
+ promoteMemberDocument,
219
+ resetPlugins,
220
+ runHook,
221
+ runHookAndCollect,
222
+ runPluginScheduledTask,
223
+ saveDocument,
224
+ schedulePluginTask,
225
+ updateMemberDocument
226
+ } from "./chunk-VGTPQXNQ.js";
227
+ import {
228
+ can
229
+ } from "./chunk-EQ2Z3KMD.js";
230
+ import {
231
+ listAuditEvents,
232
+ recordAuditEvent
233
+ } from "./chunk-RIPHIRPP.js";
234
+ import {
235
+ DEFAULT_COMMUNITY_SETTINGS,
236
+ getCommunitySettings,
237
+ updateCommunitySettings,
238
+ validateCommunitySettingsPatch
239
+ } from "./chunk-PPBWRKO2.js";
240
+ import {
241
+ createDbConnection,
242
+ generateDocumentsModule,
243
+ generateDrizzleSchema,
244
+ generateTypeScript
245
+ } from "./chunk-TFJ4MKPH.js";
246
+ import {
247
+ npMediaFoldersRelations,
248
+ npMediaRefsRelations,
249
+ npMediaRelations,
250
+ npNavigationRelations,
251
+ npRevisionsRelations,
252
+ npSessionsRelations,
253
+ npSettingsRelations,
254
+ npUsersRelations
255
+ } from "./chunk-PPAS4SZR.js";
256
+ import {
257
+ formatDate,
258
+ formatNumber,
259
+ formatRelativeTime,
260
+ getCurrentLocale,
261
+ getLocaleDirection,
262
+ resetIntlFormatterCache,
263
+ resolveLocale
264
+ } from "./chunk-MEJAHXIO.js";
265
+ import {
266
+ addStrings,
267
+ clearStringOverrideCacheForSite,
268
+ deleteStringOverride,
269
+ getAllStrings,
270
+ getStringOverride,
271
+ getStringOverridesForSite,
272
+ getStrings,
273
+ listStringOverridesForSite,
274
+ loadStringOverridesForSite,
275
+ resetStringOverrideCache,
276
+ resetStrings,
277
+ resetTranslationCache,
278
+ setStringOverride,
279
+ setStrings,
280
+ t,
281
+ tSync
282
+ } from "./chunk-QVJ2HCAX.js";
283
+ import {
284
+ getI18nConfig,
285
+ resetI18nConfig,
286
+ setI18nConfig
287
+ } from "./chunk-4ZLMEKFX.js";
288
+ import {
289
+ NP_DEFAULT_SITE_ID,
290
+ createSite,
291
+ deleteSite,
292
+ ensureDefaultSite,
293
+ getAllCollectionSlugs,
294
+ getCollectionConfig,
295
+ getCollectionRegistration,
296
+ getCollectionTable,
297
+ getDefaultSite,
298
+ getSiteByHostname,
299
+ getSiteById,
300
+ getSiteUsageSummary,
301
+ listSites,
302
+ registerCollection,
303
+ resolveSiteForHostname,
304
+ updateSite
305
+ } from "./chunk-FZ7O6DWI.js";
306
+ import {
307
+ getCurrentSiteId,
308
+ resetCurrentSiteResolver,
309
+ setCurrentSiteResolver,
310
+ withCurrentSite
311
+ } from "./chunk-SBCVAC2Z.js";
312
+ import {
313
+ NpAuthError,
314
+ NpConflictError,
315
+ NpError,
316
+ NpForbiddenError,
317
+ NpNotFoundError,
318
+ NpRateLimitError,
319
+ NpSiteContextMissingError,
320
+ NpValidationError
321
+ } from "./chunk-ZCINJSS4.js";
322
+ import {
323
+ PAUSE_SYNC_INTERVAL_MS,
324
+ PgBossAdapter,
325
+ WORKER_HEARTBEAT_INTERVAL_MS,
326
+ WORKER_STALE_THRESHOLD_MS,
327
+ buildInviteEmail,
328
+ buildResetEmail,
329
+ configureBuiltinJobContext,
330
+ countAliveWorkers,
331
+ getAllJobHandlers,
332
+ getJobHandler,
333
+ getJobsPauseState,
334
+ listWorkerHealth,
335
+ markWorkerStopped,
336
+ purgeStaleWorkers,
337
+ recordHeartbeat,
338
+ registerBuiltinHandlers,
339
+ registerJobHandler,
340
+ setJobsPauseState,
341
+ startProducer,
342
+ startWorker,
343
+ stopProducer,
344
+ stopWorker
345
+ } from "./chunk-ISLYFQWL.js";
346
+ import {
347
+ DEFAULT_JOB_LOG_RETENTION_MS,
348
+ countJobLogs,
349
+ getCurrentJobId,
350
+ listJobLogs,
351
+ pruneJobLogsOlderThan,
352
+ recordJobLog,
353
+ runInJobContext
354
+ } from "./chunk-DK2JBJH7.js";
355
+ import {
356
+ NoopEmailAdapter,
357
+ getEmailAdapter,
358
+ resetEmailAdapter,
359
+ setEmailAdapter
360
+ } from "./chunk-LSHHRDVR.js";
361
+ import {
362
+ getErrorReporter,
363
+ noopErrorReporter,
364
+ reportError,
365
+ resetErrorReporter,
366
+ setErrorReporter
367
+ } from "./chunk-WV272MPW.js";
368
+ import {
369
+ extractMediaIds
370
+ } from "./chunk-S27S42QY.js";
371
+ import {
372
+ getMediaUrl
373
+ } from "./chunk-BHK3AD3Q.js";
374
+ import {
375
+ DEFAULT_IMAGE_SIZES,
376
+ cleanupDeletedMedia,
377
+ deleteMedia,
378
+ getMediaById,
379
+ getStorageAdapter,
380
+ listMedia,
381
+ processImage,
382
+ processMediaImage,
383
+ setStorageAdapter,
384
+ uploadMedia
385
+ } from "./chunk-473S4TER.js";
386
+ import {
387
+ enqueueJob,
388
+ getJobQueue,
389
+ getOptionalJobQueue,
390
+ setJobQueue
391
+ } from "./chunk-V2UNHGAP.js";
392
+ import "./chunk-OROPGO65.js";
393
+ import {
394
+ consoleLogger,
395
+ getLogger,
396
+ getScopedLogger,
397
+ resetLogger,
398
+ setLogger
399
+ } from "./chunk-JJL74ZPK.js";
400
+ import {
401
+ getDb,
402
+ setDb
403
+ } from "./chunk-XANPEOJC.js";
404
+ import {
405
+ NP_GLOBAL_PLUGIN_SITE_ID,
406
+ npAuditEvents,
407
+ npBanKindEnum,
408
+ npBanScopeEnum,
409
+ npBans,
410
+ npCommentStatusEnum,
411
+ npComments,
412
+ npFollows,
413
+ npJobLogs,
414
+ npMedia,
415
+ npMediaFolders,
416
+ npMediaRefs,
417
+ npMediaStatusEnum,
418
+ npMemberIdentities,
419
+ npMemberMutes,
420
+ npMemberRoleScopeEnum,
421
+ npMemberRoles,
422
+ npMemberSessions,
423
+ npMemberStatusEnum,
424
+ npMembers,
425
+ npNavigation,
426
+ npNotifications,
427
+ npPasswordResetPurposeEnum,
428
+ npPluginStorage,
429
+ npPlugins,
430
+ npReactions,
431
+ npReports,
432
+ npRevisionStatusEnum,
433
+ npRevisions,
434
+ npSessions,
435
+ npSettings,
436
+ npSiteMemberships,
437
+ npSites,
438
+ npSlugHistory,
439
+ npStringOverrides,
440
+ npUserOAuthIdentities,
441
+ npUserRoleEnum,
442
+ npUsers,
443
+ npWorkerHeartbeats
444
+ } from "./chunk-M43PGOQY.js";
445
+ import "./chunk-PZ5AY32C.js";
446
+
447
+ // src/config/types.ts
448
+ var ROLE_HIERARCHY = {
449
+ viewer: 0,
450
+ author: 1,
451
+ moderator: 1,
452
+ editor: 2,
453
+ admin: 3
454
+ };
455
+
456
+ // src/config/define-config.ts
457
+ import { ZodError } from "zod";
458
+
459
+ // src/config/validation.ts
460
+ import { z } from "zod";
461
+ var functionSchema = z.custom(
462
+ (value) => typeof value === "function"
463
+ );
464
+ var fieldBaseSchema = z.object({
465
+ name: z.string().min(1),
466
+ label: z.string().min(1).optional(),
467
+ required: z.boolean().optional(),
468
+ defaultValue: z.unknown().optional(),
469
+ hidden: z.boolean().optional(),
470
+ admin: z.object({
471
+ description: z.string().min(1).optional(),
472
+ placeholder: z.string().optional(),
473
+ readOnly: z.boolean().optional(),
474
+ condition: functionSchema.optional(),
475
+ width: z.string().optional()
476
+ }).optional(),
477
+ validate: functionSchema.optional()
478
+ });
479
+ var optionSchema = z.object({
480
+ label: z.string().min(1),
481
+ value: z.string().min(1)
482
+ });
483
+ var fieldSchema = z.lazy(
484
+ () => z.discriminatedUnion("type", [
485
+ fieldBaseSchema.extend({
486
+ type: z.literal("text"),
487
+ minLength: z.number().int().nonnegative().optional(),
488
+ maxLength: z.number().int().nonnegative().optional(),
489
+ unique: z.boolean().optional()
490
+ }),
491
+ fieldBaseSchema.extend({
492
+ type: z.literal("textarea"),
493
+ minLength: z.number().int().nonnegative().optional(),
494
+ maxLength: z.number().int().nonnegative().optional(),
495
+ rows: z.number().int().positive().optional()
496
+ }),
497
+ fieldBaseSchema.extend({
498
+ type: z.literal("number"),
499
+ min: z.number().optional(),
500
+ max: z.number().optional(),
501
+ step: z.number().positive().optional(),
502
+ integerOnly: z.boolean().optional()
503
+ }),
504
+ fieldBaseSchema.extend({
505
+ type: z.literal("richText"),
506
+ editor: z.object({ features: z.array(z.string()).optional() }).optional()
507
+ }),
508
+ fieldBaseSchema.extend({
509
+ type: z.literal("blocks"),
510
+ allowedBlocks: z.array(z.string().min(1)).optional(),
511
+ minRows: z.number().int().nonnegative().optional(),
512
+ maxRows: z.number().int().nonnegative().optional()
513
+ }),
514
+ fieldBaseSchema.extend({
515
+ type: z.literal("checkbox"),
516
+ defaultValue: z.boolean().optional()
517
+ }),
518
+ fieldBaseSchema.extend({
519
+ type: z.literal("date"),
520
+ pickerOptions: z.object({
521
+ format: z.string().optional(),
522
+ includeTime: z.boolean().optional()
523
+ }).optional()
524
+ }),
525
+ fieldBaseSchema.extend({
526
+ type: z.literal("upload"),
527
+ relationTo: z.string().min(1)
528
+ }),
529
+ fieldBaseSchema.extend({
530
+ type: z.literal("relationship"),
531
+ relationTo: z.union([z.string().min(1), z.array(z.string().min(1)).min(1)]),
532
+ hasMany: z.boolean().optional(),
533
+ filterOptions: z.record(z.string(), z.unknown()).optional()
534
+ }),
535
+ fieldBaseSchema.extend({
536
+ type: z.literal("select"),
537
+ options: z.array(optionSchema).min(1),
538
+ hasMany: z.boolean().optional()
539
+ }),
540
+ fieldBaseSchema.extend({
541
+ type: z.literal("radio"),
542
+ options: z.array(optionSchema).min(1)
543
+ }),
544
+ fieldBaseSchema.extend({
545
+ type: z.literal("email")
546
+ }),
547
+ fieldBaseSchema.extend({
548
+ type: z.literal("json")
549
+ }),
550
+ fieldBaseSchema.extend({
551
+ type: z.literal("array"),
552
+ fields: z.array(fieldSchema).min(1),
553
+ minRows: z.number().int().nonnegative().optional(),
554
+ maxRows: z.number().int().nonnegative().optional()
555
+ }),
556
+ fieldBaseSchema.extend({
557
+ type: z.literal("group"),
558
+ fields: z.array(fieldSchema).min(1)
559
+ }),
560
+ z.object({
561
+ type: z.literal("row"),
562
+ fields: z.array(fieldSchema).min(1)
563
+ }),
564
+ z.object({
565
+ type: z.literal("collapsible"),
566
+ label: z.string().min(1),
567
+ fields: z.array(fieldSchema).min(1)
568
+ })
569
+ ])
570
+ );
571
+ var imageSizeSchema = z.object({
572
+ name: z.string().min(1),
573
+ width: z.number().positive(),
574
+ height: z.number().positive().optional(),
575
+ crop: z.enum(["center", "top", "bottom", "left", "right"]).optional()
576
+ });
577
+ var storageSchema = z.discriminatedUnion("adapter", [
578
+ z.object({
579
+ adapter: z.literal("local"),
580
+ local: z.object({
581
+ directory: z.string().min(1),
582
+ baseUrl: z.string().min(1)
583
+ })
584
+ }),
585
+ z.object({
586
+ adapter: z.literal("s3"),
587
+ s3: z.object({
588
+ bucket: z.string().min(1),
589
+ region: z.string().min(1),
590
+ endpoint: z.string().url().optional()
591
+ })
592
+ })
593
+ ]);
594
+ var pluginEntrySchema = z.unknown();
595
+ var npConfigSchema = z.object({
596
+ site: z.object({
597
+ name: z.string().min(1),
598
+ url: z.string().url()
599
+ }),
600
+ db: z.object({
601
+ connectionString: z.string(),
602
+ pool: z.object({
603
+ max: z.number().int().positive().optional()
604
+ }).optional()
605
+ }),
606
+ storage: storageSchema.optional(),
607
+ collections: z.array(z.lazy(() => collectionConfigSchema)),
608
+ blocks: z.array(z.unknown()).optional(),
609
+ editor: z.object({
610
+ features: z.array(z.string().min(1)).optional()
611
+ }).optional(),
612
+ images: z.object({
613
+ sizes: z.array(imageSizeSchema).optional(),
614
+ format: z.enum(["webp", "avif", "jpeg", "png"]).optional(),
615
+ quality: z.number().int().min(1).max(100).optional()
616
+ }).optional(),
617
+ auth: z.object({
618
+ secret: z.string().min(1),
619
+ tokenExpiration: z.number().int().positive().optional(),
620
+ refreshTokenExpiration: z.number().int().positive().optional(),
621
+ maxLoginAttempts: z.number().int().positive().optional(),
622
+ lockoutDuration: z.number().int().positive().optional()
623
+ }).optional(),
624
+ plugins: z.array(pluginEntrySchema).optional(),
625
+ typescript: z.unknown().optional(),
626
+ themes: z.array(z.unknown()).optional(),
627
+ i18n: z.object({
628
+ locales: z.array(z.string().min(1).max(35)).min(1),
629
+ defaultLocale: z.string().min(1)
630
+ }).refine((val) => val.locales.includes(val.defaultLocale), {
631
+ message: "defaultLocale must be one of the declared locales",
632
+ path: ["defaultLocale"]
633
+ }).optional()
634
+ });
635
+ var collectionConfigSchema = z.object({
636
+ slug: z.string().min(1).max(63).regex(/^[a-z][a-z0-9-]*$/),
637
+ labels: z.object({
638
+ singular: z.string().min(1),
639
+ plural: z.string().min(1)
640
+ }),
641
+ slugField: z.union([
642
+ z.boolean(),
643
+ z.object({
644
+ useField: z.string().min(1).optional(),
645
+ unique: z.boolean().optional()
646
+ })
647
+ ]).optional(),
648
+ i18n: z.boolean().optional(),
649
+ fields: z.array(fieldSchema).min(1),
650
+ access: z.object({
651
+ create: functionSchema.optional(),
652
+ read: functionSchema.optional(),
653
+ update: functionSchema.optional(),
654
+ delete: functionSchema.optional()
655
+ }).optional(),
656
+ hooks: z.object({
657
+ beforeCreate: z.array(functionSchema).optional(),
658
+ afterCreate: z.array(functionSchema).optional(),
659
+ beforeUpdate: z.array(functionSchema).optional(),
660
+ afterUpdate: z.array(functionSchema).optional(),
661
+ beforeDelete: z.array(functionSchema).optional(),
662
+ afterDelete: z.array(functionSchema).optional(),
663
+ beforeRead: z.array(functionSchema).optional(),
664
+ afterRead: z.array(functionSchema).optional()
665
+ }).optional(),
666
+ versions: z.object({
667
+ drafts: z.union([
668
+ z.boolean(),
669
+ z.object({
670
+ autosave: z.boolean().optional(),
671
+ autosaveInterval: z.number().int().positive().optional()
672
+ })
673
+ ]).optional(),
674
+ max: z.number().int().positive().optional()
675
+ }).optional(),
676
+ community: z.object({
677
+ comments: z.boolean().optional(),
678
+ memberWrite: z.object({
679
+ create: z.boolean().optional(),
680
+ update: z.boolean().optional(),
681
+ delete: z.boolean().optional(),
682
+ defaultStatus: z.enum(["published", "pending"]).optional()
683
+ }).optional()
684
+ }).optional(),
685
+ timestamps: z.boolean().optional(),
686
+ admin: z.object({
687
+ listColumns: z.array(z.string().min(1)).optional(),
688
+ defaultSort: z.string().min(1).optional(),
689
+ group: z.string().min(1).optional(),
690
+ hidden: z.boolean().optional(),
691
+ description: z.string().optional(),
692
+ components: z.object({
693
+ listView: z.string().optional(),
694
+ editView: z.string().optional(),
695
+ createView: z.string().optional()
696
+ }).optional()
697
+ }).optional(),
698
+ upload: z.object({
699
+ maxFileSize: z.number().positive().optional(),
700
+ allowedMimeTypes: z.array(z.string().min(1)).optional(),
701
+ imageSizes: z.array(
702
+ z.object({
703
+ name: z.string().min(1),
704
+ width: z.number().positive(),
705
+ height: z.number().positive().optional(),
706
+ crop: z.enum(["center", "top", "bottom", "left", "right"]).optional()
707
+ })
708
+ ).optional()
709
+ }).optional()
710
+ });
711
+
712
+ // src/config/define-config.ts
713
+ function defineConfig(config) {
714
+ try {
715
+ npConfigSchema.parse(config);
716
+ } catch (err) {
717
+ if (err instanceof ZodError) {
718
+ throw new Error(formatConfigError(err), { cause: err });
719
+ }
720
+ throw err;
721
+ }
722
+ if (config.i18n === void 0) {
723
+ const localized = config.collections.find((c) => c.i18n === true);
724
+ if (localized) {
725
+ throw new Error(
726
+ `Collection "${localized.slug}" sets i18n: true but the top-level config has no \`i18n\` block. Add \`i18n: { locales: [...], defaultLocale: "..." }\` to nexpress.config.ts.`
727
+ );
728
+ }
729
+ }
730
+ return config;
731
+ }
732
+ var FRIENDLY_HINTS = {
733
+ "auth.secret": "Set `NP_SECRET` in `.env` (\u226532 random chars) \u2014 `pnpm run setup` will generate one for you.",
734
+ "site.url": "Set `SITE_URL` in `.env` to your public origin \u2014 `pnpm run setup` collects it.",
735
+ "db.connectionString": "Set `DATABASE_URL` in `.env` to your Postgres connection string \u2014 `pnpm run setup` will write it.",
736
+ "storage.s3.bucket": "Set `NP_S3_BUCKET` in `.env` (or switch storage to local).",
737
+ "storage.s3.region": "Set `NP_S3_REGION` in `.env`."
738
+ };
739
+ function formatConfigError(err) {
740
+ const lines = err.issues.map((issue) => {
741
+ const path = issue.path.join(".");
742
+ const hint = FRIENDLY_HINTS[path];
743
+ if (hint) return ` \u2022 ${path}: ${hint}`;
744
+ return ` \u2022 ${path || "<root>"}: ${issue.message}`;
745
+ });
746
+ return [
747
+ "Invalid NexPress config \u2014 boot aborted before any service starts.",
748
+ "",
749
+ ...lines,
750
+ "",
751
+ "If this is your first run, `pnpm run setup` writes a working `.env`."
752
+ ].join("\n");
753
+ }
754
+
755
+ // src/config/define-collection.ts
756
+ function defineCollection(config) {
757
+ return config;
758
+ }
759
+
760
+ // src/content/helpers.ts
761
+ import { and as and2, desc, eq as eq2 } from "drizzle-orm";
762
+
763
+ // src/theme/defaults.ts
764
+ var DEFAULT_THEME = {
765
+ colors: {
766
+ primary: "oklch(0.546 0.245 262.881)",
767
+ primaryForeground: "oklch(0.985 0.001 106.423)",
768
+ background: "oklch(1 0 0)",
769
+ foreground: "oklch(0.145 0.004 285.823)",
770
+ muted: "oklch(0.967 0.001 286.375)",
771
+ mutedForeground: "oklch(0.556 0.007 286.618)",
772
+ border: "oklch(0.922 0.004 286.32)",
773
+ card: "oklch(1 0 0)",
774
+ cardForeground: "oklch(0.145 0.004 285.823)",
775
+ accent: "oklch(0.967 0.001 286.375)",
776
+ accentForeground: "oklch(0.145 0.004 285.823)",
777
+ destructive: "oklch(0.577 0.245 27.325)",
778
+ destructiveForeground: "oklch(0.985 0.001 106.423)"
779
+ },
780
+ typography: {
781
+ fontHeading: "system-ui, -apple-system, sans-serif",
782
+ fontBody: "system-ui, -apple-system, sans-serif",
783
+ fontMono: "ui-monospace, 'Cascadia Code', monospace",
784
+ fontSizeBase: "1rem",
785
+ lineHeight: "1.625",
786
+ fontSizeSm: "0.875rem",
787
+ fontSizeLg: "1.125rem",
788
+ fontSizeXl: "1.25rem",
789
+ fontSize2xl: "1.5rem",
790
+ fontSize3xl: "1.875rem",
791
+ fontSize4xl: "2.25rem"
792
+ },
793
+ shape: {
794
+ radiusSm: "0.25rem",
795
+ radiusMd: "0.375rem",
796
+ radiusLg: "0.5rem",
797
+ radiusFull: "9999px",
798
+ shadowSm: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
799
+ shadowMd: "0 4px 6px -1px rgb(0 0 0 / 0.1)",
800
+ shadowLg: "0 10px 15px -3px rgb(0 0 0 / 0.1)"
801
+ }
802
+ };
803
+
804
+ // src/themes/registry.ts
805
+ import { and, eq } from "drizzle-orm";
806
+ var registry = /* @__PURE__ */ new Map();
807
+ function registerThemes(themes) {
808
+ for (const theme of themes) {
809
+ if (!theme?.manifest?.id) {
810
+ throw new Error("Theme is missing manifest.id");
811
+ }
812
+ registry.set(theme.manifest.id, theme);
813
+ const impl = theme.impl;
814
+ if (impl?.i18n && typeof impl.i18n === "object") {
815
+ for (const [locale, bundle] of Object.entries(impl.i18n)) {
816
+ if (bundle && typeof bundle === "object") {
817
+ addStrings(locale, bundle);
818
+ }
819
+ }
820
+ }
821
+ }
822
+ }
823
+ function getRegisteredThemes() {
824
+ return Array.from(registry.values());
825
+ }
826
+ function getThemeById(id) {
827
+ return registry.get(id);
828
+ }
829
+ function resetThemes() {
830
+ registry.clear();
831
+ }
832
+ async function getActiveThemeId() {
833
+ const db = getDb();
834
+ const siteId = await getCurrentSiteId() ?? NP_DEFAULT_SITE_ID;
835
+ const rows = await db.select().from(npSettings).where(and(eq(npSettings.siteId, siteId), eq(npSettings.key, "activeTheme"))).limit(1);
836
+ const row = rows[0];
837
+ if (!row) return null;
838
+ return typeof row.value === "string" ? row.value : null;
839
+ }
840
+ async function getActiveTheme() {
841
+ const id = await getActiveThemeId();
842
+ if (id) {
843
+ const theme = registry.get(id);
844
+ if (theme) return theme;
845
+ }
846
+ const first = registry.values().next();
847
+ return first.done ? null : first.value;
848
+ }
849
+ async function setActiveThemeId(id, updatedBy = null) {
850
+ if (!registry.has(id)) {
851
+ throw new NpValidationError("Invalid input", [
852
+ {
853
+ field: "themeId",
854
+ message: `Unknown theme '${id}'. Register it in nexpress.config.ts first.`
855
+ }
856
+ ]);
857
+ }
858
+ const db = getDb();
859
+ const now = /* @__PURE__ */ new Date();
860
+ const siteId = await getCurrentSiteId() ?? NP_DEFAULT_SITE_ID;
861
+ await db.insert(npSettings).values({ siteId, key: "activeTheme", value: id, updatedAt: now, updatedBy }).onConflictDoUpdate({
862
+ target: [npSettings.siteId, npSettings.key],
863
+ set: { value: id, updatedAt: now, updatedBy }
864
+ });
865
+ }
866
+ async function getThemeTemplateSummaries(collectionSlug) {
867
+ const summaries = /* @__PURE__ */ new Map();
868
+ const { getPluginTemplatesForCollection: getPluginTemplatesForCollection2 } = await import("./templates-IFVJMCJ6.js");
869
+ for (const [id, value] of getPluginTemplatesForCollection2(collectionSlug)) {
870
+ const def = value;
871
+ summaries.set(id, {
872
+ id,
873
+ label: typeof def.label === "string" ? def.label : id,
874
+ description: typeof def.description === "string" ? def.description : void 0
875
+ });
876
+ }
877
+ const active = await getActiveTheme();
878
+ if (active) {
879
+ const impl = active.impl;
880
+ const set = impl.templates?.[collectionSlug];
881
+ if (set) {
882
+ for (const [id, def] of Object.entries(set)) {
883
+ summaries.set(id, {
884
+ id,
885
+ label: typeof def.label === "string" ? def.label : id,
886
+ description: typeof def.description === "string" ? def.description : void 0
887
+ });
888
+ }
889
+ }
890
+ }
891
+ return [...summaries.values()];
892
+ }
893
+ async function resolveTemplateComponent(collectionSlug, templateId) {
894
+ const active = await getActiveTheme();
895
+ if (active) {
896
+ const impl = active.impl;
897
+ const themeEntry = impl.templates?.[collectionSlug]?.[templateId];
898
+ if (themeEntry) return themeEntry;
899
+ }
900
+ const { getPluginTemplatesForCollection: getPluginTemplatesForCollection2 } = await import("./templates-IFVJMCJ6.js");
901
+ const pluginEntry = getPluginTemplatesForCollection2(collectionSlug).get(templateId);
902
+ return pluginEntry ?? null;
903
+ }
904
+
905
+ // src/content/helpers.ts
906
+ async function resolveSiteId() {
907
+ return await getCurrentSiteId() ?? NP_DEFAULT_SITE_ID;
908
+ }
909
+ async function getTheme() {
910
+ const db = getDb();
911
+ const siteId = await resolveSiteId();
912
+ const rows = await db.select().from(npSettings).where(and2(eq2(npSettings.siteId, siteId), eq2(npSettings.key, "theme"))).limit(1);
913
+ const active = await getActiveTheme();
914
+ const themeOverlay = active?.impl?.tokens;
915
+ const dbOverlay = rows[0]?.value;
916
+ if (!themeOverlay && !dbOverlay) return DEFAULT_THEME;
917
+ return mergeThemeTokens(DEFAULT_THEME, themeOverlay, dbOverlay);
918
+ }
919
+ function mergeThemeTokens(base, ...overlays) {
920
+ const result = {
921
+ colors: { ...base.colors },
922
+ typography: { ...base.typography },
923
+ shape: { ...base.shape }
924
+ };
925
+ for (const overlay of overlays) {
926
+ if (!overlay) continue;
927
+ if (overlay.colors) Object.assign(result.colors, overlay.colors);
928
+ if (overlay.typography) Object.assign(result.typography, overlay.typography);
929
+ if (overlay.shape) Object.assign(result.shape, overlay.shape);
930
+ }
931
+ return result;
932
+ }
933
+ async function getNavigation(location = "header") {
934
+ const db = getDb();
935
+ const siteId = await resolveSiteId();
936
+ const rows = await db.select().from(npNavigation).where(
937
+ and2(eq2(npNavigation.siteId, siteId), eq2(npNavigation.location, location))
938
+ ).limit(1);
939
+ if (rows.length === 0 || !rows[0]) {
940
+ return [];
941
+ }
942
+ return resolveNavItemUrls(rows[0].items);
943
+ }
944
+ async function resolveNavItemUrls(items) {
945
+ const refsByCollection = collectPageRefs(items);
946
+ const docByKey = /* @__PURE__ */ new Map();
947
+ await Promise.all(
948
+ [...refsByCollection.entries()].map(async ([collection, ids]) => {
949
+ try {
950
+ await Promise.all(
951
+ ids.map(async (id) => {
952
+ const result = await findDocuments(collection, {
953
+ where: { id, status: "published" },
954
+ limit: 1
955
+ });
956
+ const doc = result.docs[0];
957
+ if (doc) docByKey.set(`${collection}\0${id}`, doc);
958
+ })
959
+ );
960
+ } catch {
961
+ }
962
+ })
963
+ );
964
+ return items.map((item) => mapNavItem(item, docByKey));
965
+ }
966
+ function collectPageRefs(items) {
967
+ const out = /* @__PURE__ */ new Map();
968
+ const walk = (arr) => {
969
+ for (const item of arr) {
970
+ if (item.type === "page" && item.pageId) {
971
+ const slug = item.collectionSlug ?? "pages";
972
+ const ids = out.get(slug) ?? [];
973
+ ids.push(item.pageId);
974
+ out.set(slug, ids);
975
+ }
976
+ if (item.children) walk(item.children);
977
+ }
978
+ };
979
+ walk(items);
980
+ return out;
981
+ }
982
+ function mapNavItem(item, docByKey) {
983
+ const children = item.children ? item.children.map((child) => mapNavItem(child, docByKey)) : void 0;
984
+ const withChildren = children ? { ...item, children } : item;
985
+ if (item.type === "page" && item.pageId) {
986
+ const collection = item.collectionSlug ?? "pages";
987
+ const doc = docByKey.get(`${collection}\0${item.pageId}`);
988
+ let url = "#";
989
+ if (doc) {
990
+ try {
991
+ const config = getCollectionConfig(collection);
992
+ const path = config.seo?.urlPath?.(doc);
993
+ if (path) url = path;
994
+ } catch {
995
+ }
996
+ }
997
+ return { ...withChildren, url };
998
+ }
999
+ if (item.type === "collection" && item.collection) {
1000
+ const slug = item.collection.replace(/^\/+/, "");
1001
+ const url = slug ? `/${slug}` : "#";
1002
+ return { ...withChildren, url };
1003
+ }
1004
+ return withChildren;
1005
+ }
1006
+ async function getPageBySlug(slug, options) {
1007
+ const where = { slug: slug || "/" };
1008
+ if (!options?.draft) {
1009
+ where.status = "published";
1010
+ }
1011
+ const result = await findDocuments("pages", {
1012
+ where,
1013
+ locale: options?.locale,
1014
+ limit: 1
1015
+ });
1016
+ return result.docs[0] ?? null;
1017
+ }
1018
+ async function getPostBySlug(slug, options) {
1019
+ const where = { slug };
1020
+ if (!options?.draft) {
1021
+ where.status = "published";
1022
+ }
1023
+ const result = await findDocuments("posts", {
1024
+ where,
1025
+ limit: 1
1026
+ });
1027
+ return result.docs[0] ?? null;
1028
+ }
1029
+ async function findPosts(options, user) {
1030
+ return findDocuments("posts", options, user);
1031
+ }
1032
+ async function getAllPageSlugs() {
1033
+ const result = await findDocuments("pages", {
1034
+ limit: 1e4
1035
+ });
1036
+ return result.docs.map((doc) => doc.slug).filter(Boolean);
1037
+ }
1038
+ var SLUG_REDIRECT_MAX_HOPS = 5;
1039
+ async function findSlugRedirect(collection, oldSlug) {
1040
+ if (!oldSlug || oldSlug.length === 0) return null;
1041
+ const db = getDb();
1042
+ const siteId = await resolveSiteId();
1043
+ const seen = /* @__PURE__ */ new Set([oldSlug]);
1044
+ let currentOld = oldSlug;
1045
+ let resolved = null;
1046
+ for (let hop = 0; hop < SLUG_REDIRECT_MAX_HOPS; hop++) {
1047
+ const [latest] = await db.select().from(npSlugHistory).where(
1048
+ and2(
1049
+ eq2(npSlugHistory.siteId, siteId),
1050
+ eq2(npSlugHistory.collection, collection),
1051
+ eq2(npSlugHistory.oldSlug, currentOld)
1052
+ )
1053
+ ).orderBy(desc(npSlugHistory.createdAt)).limit(1);
1054
+ if (!latest) break;
1055
+ const next = latest.newSlug;
1056
+ if (next === oldSlug || seen.has(next)) {
1057
+ break;
1058
+ }
1059
+ resolved = next;
1060
+ seen.add(next);
1061
+ currentOld = next;
1062
+ }
1063
+ return resolved;
1064
+ }
1065
+ async function getSetting(key) {
1066
+ const db = getDb();
1067
+ const siteId = await resolveSiteId();
1068
+ const rows = await db.select().from(npSettings).where(and2(eq2(npSettings.siteId, siteId), eq2(npSettings.key, key))).limit(1);
1069
+ if (rows.length === 0 || !rows[0]) {
1070
+ return null;
1071
+ }
1072
+ return rows[0].value;
1073
+ }
1074
+
1075
+ // src/storage/local.ts
1076
+ import { createReadStream, createWriteStream } from "fs";
1077
+ import { access, mkdir, unlink, writeFile } from "fs/promises";
1078
+ import { dirname, join } from "path";
1079
+ import { Readable } from "stream";
1080
+ import { pipeline } from "stream/promises";
1081
+ var LocalStorageAdapter = class {
1082
+ constructor(config) {
1083
+ this.config = config;
1084
+ }
1085
+ config;
1086
+ async upload(key, data, _) {
1087
+ const filePath = this.resolvePath(key);
1088
+ await mkdir(dirname(filePath), { recursive: true });
1089
+ if (Buffer.isBuffer(data)) {
1090
+ await writeFile(filePath, data);
1091
+ return;
1092
+ }
1093
+ await pipeline(Readable.fromWeb(data), createWriteStream(filePath));
1094
+ }
1095
+ getStream(key) {
1096
+ return Promise.resolve(
1097
+ Readable.toWeb(createReadStream(this.resolvePath(key)))
1098
+ );
1099
+ }
1100
+ getUrl(key) {
1101
+ const base = this.normalizeBaseUrl(this.config.baseUrl);
1102
+ if (base.startsWith("/")) {
1103
+ return Promise.resolve(`${base}/${key}`);
1104
+ }
1105
+ return Promise.resolve(new URL(key, `${base}/`).toString());
1106
+ }
1107
+ async delete(key) {
1108
+ await unlink(this.resolvePath(key));
1109
+ }
1110
+ async exists(key) {
1111
+ try {
1112
+ await access(this.resolvePath(key));
1113
+ return true;
1114
+ } catch {
1115
+ return false;
1116
+ }
1117
+ }
1118
+ resolvePath(key) {
1119
+ return join(this.config.directory, key);
1120
+ }
1121
+ normalizeBaseUrl(baseUrl) {
1122
+ return baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
1123
+ }
1124
+ };
1125
+
1126
+ // src/storage/s3.ts
1127
+ import { Readable as Readable2 } from "stream";
1128
+ var s3ModulePromise = null;
1129
+ var S3StorageAdapter = class {
1130
+ constructor(config) {
1131
+ this.config = config;
1132
+ }
1133
+ config;
1134
+ clientPromise = null;
1135
+ async upload(key, data, metadata) {
1136
+ const [{ PutObjectCommand }, client] = await Promise.all([
1137
+ loadS3Module(),
1138
+ this.getClient()
1139
+ ]);
1140
+ await client.send(
1141
+ new PutObjectCommand({
1142
+ Bucket: this.config.bucket,
1143
+ Key: key,
1144
+ Body: Buffer.isBuffer(data) ? data : Readable2.fromWeb(data),
1145
+ ContentType: metadata.contentType,
1146
+ ContentLength: metadata.contentLength,
1147
+ Metadata: {
1148
+ originalFilename: metadata.originalFilename
1149
+ }
1150
+ })
1151
+ );
1152
+ }
1153
+ async getStream(key) {
1154
+ const [{ GetObjectCommand }, client] = await Promise.all([
1155
+ loadS3Module(),
1156
+ this.getClient()
1157
+ ]);
1158
+ const response = await client.send(
1159
+ new GetObjectCommand({
1160
+ Bucket: this.config.bucket,
1161
+ Key: key
1162
+ })
1163
+ );
1164
+ return toReadableStream(response.Body);
1165
+ }
1166
+ getUrl(key) {
1167
+ if (this.config.endpoint) {
1168
+ return Promise.resolve(
1169
+ new URL(
1170
+ key,
1171
+ `${normalizeUrl(this.config.endpoint)}/${this.config.bucket}/`
1172
+ ).toString()
1173
+ );
1174
+ }
1175
+ return Promise.resolve(
1176
+ new URL(
1177
+ key,
1178
+ `https://${this.config.bucket}.s3.${this.config.region}.amazonaws.com/`
1179
+ ).toString()
1180
+ );
1181
+ }
1182
+ async delete(key) {
1183
+ const [{ DeleteObjectCommand }, client] = await Promise.all([
1184
+ loadS3Module(),
1185
+ this.getClient()
1186
+ ]);
1187
+ await client.send(
1188
+ new DeleteObjectCommand({
1189
+ Bucket: this.config.bucket,
1190
+ Key: key
1191
+ })
1192
+ );
1193
+ }
1194
+ async exists(key) {
1195
+ const [{ HeadObjectCommand }, client] = await Promise.all([
1196
+ loadS3Module(),
1197
+ this.getClient()
1198
+ ]);
1199
+ try {
1200
+ await client.send(
1201
+ new HeadObjectCommand({
1202
+ Bucket: this.config.bucket,
1203
+ Key: key
1204
+ })
1205
+ );
1206
+ return true;
1207
+ } catch (error) {
1208
+ if (isNotFoundError(error)) {
1209
+ return false;
1210
+ }
1211
+ throw error;
1212
+ }
1213
+ }
1214
+ getClient() {
1215
+ if (!this.clientPromise) {
1216
+ this.clientPromise = this.createClient();
1217
+ }
1218
+ return this.clientPromise;
1219
+ }
1220
+ async createClient() {
1221
+ const { S3Client } = await loadS3Module();
1222
+ return new S3Client({
1223
+ region: this.config.region,
1224
+ endpoint: this.config.endpoint,
1225
+ credentials: this.config.credentials,
1226
+ forcePathStyle: Boolean(this.config.endpoint)
1227
+ });
1228
+ }
1229
+ };
1230
+ async function loadS3Module() {
1231
+ s3ModulePromise ??= import("@aws-sdk/client-s3");
1232
+ return s3ModulePromise;
1233
+ }
1234
+ function toReadableStream(body) {
1235
+ if (hasTransformToWebStream(body)) {
1236
+ return body.transformToWebStream();
1237
+ }
1238
+ if (body instanceof Readable2) {
1239
+ return Readable2.toWeb(body);
1240
+ }
1241
+ throw new Error("S3 object body is not a readable stream.");
1242
+ }
1243
+ function hasTransformToWebStream(value) {
1244
+ return typeof value === "object" && value !== null && "transformToWebStream" in value && typeof value.transformToWebStream === "function";
1245
+ }
1246
+ function isNotFoundError(error) {
1247
+ return typeof error === "object" && error !== null && ("name" in error && error.name === "NotFound" || "$metadata" in error && typeof error.$metadata === "object" && error.$metadata !== null && "httpStatusCode" in error.$metadata && error.$metadata.httpStatusCode === 404);
1248
+ }
1249
+ function normalizeUrl(value) {
1250
+ return value.endsWith("/") ? value.slice(0, -1) : value;
1251
+ }
1252
+
1253
+ // src/storage/index.ts
1254
+ function createStorageAdapter(config) {
1255
+ if (!config) {
1256
+ throw new Error("Storage configuration is required.");
1257
+ }
1258
+ if (config.adapter === "local") {
1259
+ if (!config.local) {
1260
+ throw new Error("Local storage configuration is required.");
1261
+ }
1262
+ return new LocalStorageAdapter(config.local);
1263
+ }
1264
+ if (!config.s3) {
1265
+ throw new Error("S3 storage configuration is required.");
1266
+ }
1267
+ const s3Config = config.s3;
1268
+ return new S3StorageAdapter(s3Config);
1269
+ }
1270
+
1271
+ // src/email/smtp.ts
1272
+ var SmtpEmailAdapter = class {
1273
+ kind = "smtp";
1274
+ options;
1275
+ transporter = null;
1276
+ constructor(options) {
1277
+ this.options = options;
1278
+ }
1279
+ async ensureTransporter() {
1280
+ if (this.transporter) return this.transporter;
1281
+ let nodemailer;
1282
+ try {
1283
+ const moduleId = "nodemailer";
1284
+ nodemailer = await import(moduleId);
1285
+ } catch (error) {
1286
+ const cause = error instanceof Error ? error.message : String(error);
1287
+ throw new NpError(
1288
+ `Could not load \`nodemailer\` \u2014 add it to the app's dependencies to use the SMTP adapter. Cause: ${cause}`,
1289
+ "EMAIL_ADAPTER_MISSING_DEPENDENCY",
1290
+ 500
1291
+ );
1292
+ }
1293
+ const { host, port, user, pass } = this.options;
1294
+ const secure = this.options.secure ?? port === 465;
1295
+ this.transporter = nodemailer.createTransport({
1296
+ host,
1297
+ port,
1298
+ secure,
1299
+ auth: user && pass ? { user, pass } : void 0
1300
+ });
1301
+ return this.transporter;
1302
+ }
1303
+ async send(message) {
1304
+ const transporter = await this.ensureTransporter();
1305
+ try {
1306
+ await transporter.sendMail({
1307
+ from: message.from ?? this.options.from,
1308
+ to: message.to,
1309
+ subject: message.subject,
1310
+ text: message.text,
1311
+ html: message.html
1312
+ });
1313
+ } catch (error) {
1314
+ const cause = error instanceof Error ? error.message : String(error);
1315
+ throw new NpError(
1316
+ `Failed to deliver email via SMTP: ${cause}`,
1317
+ "EMAIL_DELIVERY_FAILED",
1318
+ 502
1319
+ );
1320
+ }
1321
+ }
1322
+ };
1323
+
1324
+ // src/theme/sanitize.ts
1325
+ function sanitizeTokenValue(value) {
1326
+ return value.replace(/[;{}]/g, "").replace(/url\s*\(/gi, "").replace(/expression\s*\(/gi, "").replace(/@import/gi, "").slice(0, 200);
1327
+ }
1328
+
1329
+ // src/themes/requirements.ts
1330
+ function flattenTopLevelFields(fields) {
1331
+ const out = /* @__PURE__ */ new Map();
1332
+ for (const f of fields) {
1333
+ if (f.type === "row" || f.type === "collapsible") {
1334
+ for (const [name, child] of flattenTopLevelFields(f.fields)) {
1335
+ out.set(name, child);
1336
+ }
1337
+ continue;
1338
+ }
1339
+ if ("name" in f && typeof f.name === "string") {
1340
+ out.set(f.name, f);
1341
+ }
1342
+ }
1343
+ return out;
1344
+ }
1345
+ function relationToMatches(expected, actual) {
1346
+ const expectedList = Array.isArray(expected) ? expected : [expected];
1347
+ const actualList = Array.isArray(actual) ? actual : [actual];
1348
+ return expectedList.every((e) => actualList.includes(e));
1349
+ }
1350
+ function checkThemeRequirements(manifest, collections) {
1351
+ const result = {
1352
+ themeId: manifest.id,
1353
+ hasMismatches: false,
1354
+ hasHardMismatches: false,
1355
+ missingCollections: [],
1356
+ missingFields: [],
1357
+ typeConflicts: [],
1358
+ relationConflicts: []
1359
+ };
1360
+ const requires = manifest.requires?.collections;
1361
+ if (!requires) return result;
1362
+ const bySlug = new Map(collections.map((c) => [c.slug, c]));
1363
+ for (const [slug, req] of Object.entries(requires)) {
1364
+ const collection = bySlug.get(slug);
1365
+ if (!collection) {
1366
+ result.missingCollections.push({
1367
+ collection: slug,
1368
+ createIfAbsent: req.createIfAbsent ?? false
1369
+ });
1370
+ continue;
1371
+ }
1372
+ if (!req.fields) continue;
1373
+ const fieldMap = flattenTopLevelFields(collection.fields);
1374
+ for (const [fieldName, fieldReq] of Object.entries(req.fields)) {
1375
+ const hard = fieldReq.hard ?? true;
1376
+ const actual = fieldMap.get(fieldName);
1377
+ if (!actual) {
1378
+ result.missingFields.push({
1379
+ collection: slug,
1380
+ field: fieldName,
1381
+ expected: fieldReq,
1382
+ hard
1383
+ });
1384
+ continue;
1385
+ }
1386
+ if (actual.type !== fieldReq.type) {
1387
+ result.typeConflicts.push({
1388
+ collection: slug,
1389
+ field: fieldName,
1390
+ expected: fieldReq.type,
1391
+ actual: actual.type,
1392
+ hard
1393
+ });
1394
+ continue;
1395
+ }
1396
+ if (fieldReq.type === "relationship" && fieldReq.relationTo && actual.type === "relationship") {
1397
+ if (!relationToMatches(
1398
+ fieldReq.relationTo,
1399
+ actual.relationTo
1400
+ )) {
1401
+ result.relationConflicts.push({
1402
+ collection: slug,
1403
+ field: fieldName,
1404
+ expected: fieldReq.relationTo,
1405
+ actual: actual.relationTo,
1406
+ hard
1407
+ });
1408
+ }
1409
+ }
1410
+ }
1411
+ }
1412
+ const hardMismatches = result.missingCollections.length > 0 || result.missingFields.some((m) => m.hard) || result.typeConflicts.some((c) => c.hard) || result.relationConflicts.some((c) => c.hard);
1413
+ const anyMismatches = result.missingCollections.length > 0 || result.missingFields.length > 0 || result.typeConflicts.length > 0 || result.relationConflicts.length > 0;
1414
+ result.hasHardMismatches = hardMismatches;
1415
+ result.hasMismatches = anyMismatches;
1416
+ return result;
1417
+ }
1418
+
1419
+ // src/themes/settings.ts
1420
+ import { and as and3, eq as eq3 } from "drizzle-orm";
1421
+ var DEFAULT_SITE = "default";
1422
+ function settingsKey(themeId) {
1423
+ return `theme.settings:${themeId}`;
1424
+ }
1425
+ function isVersionedSettings(value) {
1426
+ if (!value || typeof value !== "object") return false;
1427
+ const candidate = value;
1428
+ return typeof candidate.__npVersion === "number" && Number.isFinite(candidate.__npVersion) && "__npSettings" in candidate;
1429
+ }
1430
+ function applyMigration(manifest, rawValue, fromVersion) {
1431
+ const target = manifest.settingsVersion ?? 1;
1432
+ if (fromVersion >= target) return rawValue;
1433
+ const migrate = manifest.settingsMigrate;
1434
+ if (typeof migrate !== "function") return rawValue;
1435
+ try {
1436
+ return migrate(rawValue, fromVersion);
1437
+ } catch {
1438
+ return rawValue;
1439
+ }
1440
+ }
1441
+ function defaultsFrom(fields) {
1442
+ const out = {};
1443
+ for (const f of fields) {
1444
+ if (f.default !== void 0) {
1445
+ out[f.name] = f.default;
1446
+ continue;
1447
+ }
1448
+ if (f.type === "object") {
1449
+ out[f.name] = defaultsFrom(f.fields);
1450
+ }
1451
+ if (f.type === "array") {
1452
+ out[f.name] = [];
1453
+ }
1454
+ }
1455
+ return out;
1456
+ }
1457
+ async function getThemeSettings(themeId) {
1458
+ const result = await getThemeSettingsWithStatus(themeId);
1459
+ return result.value;
1460
+ }
1461
+ async function getThemeSettingsWithStatus(themeId) {
1462
+ const theme = themeId ? getThemeById(themeId) : await getActiveTheme();
1463
+ if (!theme) {
1464
+ return { themeId: null, value: {}, hasPersisted: false };
1465
+ }
1466
+ const schema = theme.manifest.settingsSchema;
1467
+ if (!schema) {
1468
+ return { themeId: theme.manifest.id, value: {}, hasPersisted: false };
1469
+ }
1470
+ const db = getDb();
1471
+ const siteId = await getCurrentSiteId() ?? DEFAULT_SITE;
1472
+ const rows = await db.select().from(npSettings).where(
1473
+ and3(
1474
+ eq3(npSettings.siteId, siteId),
1475
+ eq3(npSettings.key, settingsKey(theme.manifest.id))
1476
+ )
1477
+ ).limit(1);
1478
+ const fields = introspectThemeSettingsSchema(schema);
1479
+ const defaults = defaultsFrom(fields);
1480
+ const row = rows[0];
1481
+ if (!row) {
1482
+ const parsed2 = schema.safeParse(defaults);
1483
+ return {
1484
+ themeId: theme.manifest.id,
1485
+ value: parsed2.success ? parsed2.data : defaults,
1486
+ hasPersisted: false
1487
+ };
1488
+ }
1489
+ const versioned = isVersionedSettings(row.value) ? row.value : null;
1490
+ const storedVersion = versioned ? versioned.__npVersion : 1;
1491
+ const rawValue = versioned ? versioned.__npSettings : row.value;
1492
+ const valueToParse = applyMigration(theme.manifest, rawValue, storedVersion);
1493
+ const parsed = schema.safeParse(valueToParse);
1494
+ if (parsed.success) {
1495
+ return {
1496
+ themeId: theme.manifest.id,
1497
+ value: parsed.data,
1498
+ hasPersisted: true
1499
+ };
1500
+ }
1501
+ return {
1502
+ themeId: theme.manifest.id,
1503
+ value: defaults,
1504
+ hasPersisted: true,
1505
+ parseError: parsed.error.message
1506
+ };
1507
+ }
1508
+ async function setThemeSettings(themeId, value, updatedBy = null) {
1509
+ const theme = getThemeById(themeId);
1510
+ if (!theme) {
1511
+ throw new NpValidationError("Invalid input", [
1512
+ {
1513
+ field: "themeId",
1514
+ message: `Unknown theme '${themeId}'. Register it in nexpress.config.ts first.`
1515
+ }
1516
+ ]);
1517
+ }
1518
+ const schema = theme.manifest.settingsSchema;
1519
+ if (!schema) {
1520
+ throw new NpValidationError("Invalid input", [
1521
+ {
1522
+ field: "themeId",
1523
+ message: `Theme '${themeId}' does not declare a settingsSchema.`
1524
+ }
1525
+ ]);
1526
+ }
1527
+ const parsed = schema.safeParse(value);
1528
+ if (!parsed.success) {
1529
+ throw new NpValidationError(
1530
+ "Settings failed validation",
1531
+ parsed.error.issues.map((i) => ({
1532
+ field: i.path.join("."),
1533
+ message: i.message
1534
+ }))
1535
+ );
1536
+ }
1537
+ const wrapped = {
1538
+ __npVersion: theme.manifest.settingsVersion ?? 1,
1539
+ __npSettings: parsed.data
1540
+ };
1541
+ const db = getDb();
1542
+ const now = /* @__PURE__ */ new Date();
1543
+ const siteId = await getCurrentSiteId() ?? DEFAULT_SITE;
1544
+ await db.insert(npSettings).values({
1545
+ siteId,
1546
+ key: settingsKey(themeId),
1547
+ value: wrapped,
1548
+ updatedAt: now,
1549
+ updatedBy
1550
+ }).onConflictDoUpdate({
1551
+ target: [npSettings.siteId, npSettings.key],
1552
+ set: { value: wrapped, updatedAt: now, updatedBy }
1553
+ });
1554
+ return parsed.data;
1555
+ }
1556
+ async function activeThemeContributesSeo() {
1557
+ const theme = await getActiveTheme();
1558
+ if (!theme) return false;
1559
+ const impl = theme.impl;
1560
+ if (!impl?.seo) return false;
1561
+ return Boolean(impl.seo.sitemapEntries || impl.seo.feedEntries);
1562
+ }
1563
+
1564
+ // src/themes/nav-locations.ts
1565
+ function extractNavLocationsFromImpl(impl) {
1566
+ const shape = impl;
1567
+ const declared = shape?.navLocations;
1568
+ if (!declared || typeof declared !== "object") return [];
1569
+ const out = [];
1570
+ for (const [key, raw] of Object.entries(declared)) {
1571
+ if (!raw || typeof raw !== "object") continue;
1572
+ if (typeof raw.label !== "string") continue;
1573
+ out.push({
1574
+ key,
1575
+ label: raw.label,
1576
+ description: typeof raw.description === "string" ? raw.description : void 0,
1577
+ maxItems: typeof raw.maxItems === "number" ? raw.maxItems : void 0
1578
+ });
1579
+ }
1580
+ return out;
1581
+ }
1582
+ async function getActiveThemeNavLocations() {
1583
+ const theme = await getActiveTheme();
1584
+ if (!theme) return [];
1585
+ return extractNavLocationsFromImpl(theme.impl);
1586
+ }
1587
+
1588
+ // src/themes/error-seo.ts
1589
+ function extractNotFoundComponent(impl) {
1590
+ const shape = impl;
1591
+ return typeof shape?.notFound === "function" ? shape.notFound : null;
1592
+ }
1593
+ function extractErrorComponent(impl) {
1594
+ const shape = impl;
1595
+ return typeof shape?.error === "function" ? shape.error : null;
1596
+ }
1597
+ function extractMembersNotFoundComponent(impl) {
1598
+ const shape = impl;
1599
+ const memberLevel = shape?.members?.notFound;
1600
+ if (typeof memberLevel === "function") return memberLevel;
1601
+ return typeof shape?.notFound === "function" ? shape.notFound : null;
1602
+ }
1603
+ function extractSeoHooks(impl) {
1604
+ const shape = impl;
1605
+ const seo = shape?.seo;
1606
+ if (!seo || typeof seo !== "object") return {};
1607
+ const out = {};
1608
+ if (typeof seo.sitemapEntries === "function") {
1609
+ out.sitemapEntries = seo.sitemapEntries;
1610
+ }
1611
+ if (typeof seo.feedEntries === "function") {
1612
+ out.feedEntries = seo.feedEntries;
1613
+ }
1614
+ if (typeof seo.robotsTxt === "function") {
1615
+ out.robotsTxt = seo.robotsTxt;
1616
+ }
1617
+ return out;
1618
+ }
1619
+ async function getActiveThemeNotFound() {
1620
+ const theme = await getActiveTheme();
1621
+ if (!theme) return null;
1622
+ return extractNotFoundComponent(theme.impl);
1623
+ }
1624
+ async function getActiveThemeError() {
1625
+ const theme = await getActiveTheme();
1626
+ if (!theme) return null;
1627
+ return extractErrorComponent(theme.impl);
1628
+ }
1629
+ async function getActiveThemeMembersNotFound() {
1630
+ const theme = await getActiveTheme();
1631
+ if (!theme) return null;
1632
+ return extractMembersNotFoundComponent(theme.impl);
1633
+ }
1634
+ async function getActiveThemeSeoHooks() {
1635
+ const theme = await getActiveTheme();
1636
+ if (!theme) return {};
1637
+ return extractSeoHooks(theme.impl);
1638
+ }
1639
+
1640
+ // src/sites/memberships.ts
1641
+ import { and as and4, eq as eq4 } from "drizzle-orm";
1642
+ async function listSiteMemberships(siteId) {
1643
+ const db = getDb();
1644
+ const rows = await db.select().from(npSiteMemberships).where(eq4(npSiteMemberships.siteId, siteId));
1645
+ return rows.map((row) => ({
1646
+ siteId: row.siteId,
1647
+ userId: row.userId,
1648
+ role: row.role,
1649
+ createdAt: row.createdAt,
1650
+ updatedAt: row.updatedAt
1651
+ }));
1652
+ }
1653
+ async function listMembershipsForUser(userId) {
1654
+ const db = getDb();
1655
+ const rows = await db.select().from(npSiteMemberships).where(eq4(npSiteMemberships.userId, userId));
1656
+ return rows.map((row) => ({
1657
+ siteId: row.siteId,
1658
+ userId: row.userId,
1659
+ role: row.role,
1660
+ createdAt: row.createdAt,
1661
+ updatedAt: row.updatedAt
1662
+ }));
1663
+ }
1664
+ async function getMembership(siteId, userId) {
1665
+ const db = getDb();
1666
+ const [row] = await db.select().from(npSiteMemberships).where(
1667
+ and4(
1668
+ eq4(npSiteMemberships.siteId, siteId),
1669
+ eq4(npSiteMemberships.userId, userId)
1670
+ )
1671
+ ).limit(1);
1672
+ if (!row) return null;
1673
+ return {
1674
+ siteId: row.siteId,
1675
+ userId: row.userId,
1676
+ role: row.role,
1677
+ createdAt: row.createdAt,
1678
+ updatedAt: row.updatedAt
1679
+ };
1680
+ }
1681
+ async function grantSiteMembership(siteId, userId, role) {
1682
+ const db = getDb();
1683
+ const now = /* @__PURE__ */ new Date();
1684
+ const [row] = await db.insert(npSiteMemberships).values({ siteId, userId, role, createdAt: now, updatedAt: now }).onConflictDoUpdate({
1685
+ target: [npSiteMemberships.siteId, npSiteMemberships.userId],
1686
+ set: { role, updatedAt: now }
1687
+ }).returning();
1688
+ if (!row) throw new Error("Failed to grant membership");
1689
+ return {
1690
+ siteId: row.siteId,
1691
+ userId: row.userId,
1692
+ role: row.role,
1693
+ createdAt: row.createdAt,
1694
+ updatedAt: row.updatedAt
1695
+ };
1696
+ }
1697
+ async function revokeSiteMembership(siteId, userId) {
1698
+ const db = getDb();
1699
+ await db.delete(npSiteMemberships).where(
1700
+ and4(
1701
+ eq4(npSiteMemberships.siteId, siteId),
1702
+ eq4(npSiteMemberships.userId, userId)
1703
+ )
1704
+ );
1705
+ }
1706
+ async function setSuperAdmin(userId, isSuperAdmin2) {
1707
+ const db = getDb();
1708
+ const result = await db.update(npUsers).set({ isSuperAdmin: isSuperAdmin2, updatedAt: /* @__PURE__ */ new Date() }).where(eq4(npUsers.id, userId)).returning({ id: npUsers.id });
1709
+ if (result.length === 0) {
1710
+ throw new NpValidationError("Invalid input", [
1711
+ { field: "userId", message: `User "${userId}" not found` }
1712
+ ]);
1713
+ }
1714
+ }
1715
+ var ROLE_RANK = {
1716
+ viewer: 0,
1717
+ author: 1,
1718
+ moderator: 2,
1719
+ editor: 3,
1720
+ admin: 4
1721
+ };
1722
+ async function resolveUserRoleOnSite(user, siteId) {
1723
+ const db = getDb();
1724
+ const [row] = await db.select({ isSuperAdmin: npUsers.isSuperAdmin, role: npUsers.role }).from(npUsers).where(eq4(npUsers.id, user.id)).limit(1);
1725
+ if (!row) return user.role;
1726
+ if (row.isSuperAdmin) return "admin";
1727
+ const membership = await getMembership(siteId, user.id);
1728
+ if (membership) return membership.role;
1729
+ return row.role;
1730
+ }
1731
+ async function hasRoleOnSite(user, minRole, siteId) {
1732
+ const targetSite = siteId ?? await getCurrentSiteId() ?? NP_DEFAULT_SITE_ID;
1733
+ const role = await resolveUserRoleOnSite(user, targetSite);
1734
+ return ROLE_RANK[role] >= ROLE_RANK[minRole];
1735
+ }
1736
+ async function isSuperAdmin(user) {
1737
+ const db = getDb();
1738
+ const [row] = await db.select({ isSuperAdmin: npUsers.isSuperAdmin }).from(npUsers).where(eq4(npUsers.id, user.id)).limit(1);
1739
+ return Boolean(row?.isSuperAdmin);
1740
+ }
1741
+
1742
+ // src/plugins/persistence.ts
1743
+ import { eq as eq5 } from "drizzle-orm";
1744
+ function toState(row) {
1745
+ return {
1746
+ id: row.id,
1747
+ enabled: row.enabled,
1748
+ installedAt: row.installedAt,
1749
+ updatedAt: row.updatedAt
1750
+ };
1751
+ }
1752
+ async function listPluginStates(db) {
1753
+ const rows = await db.select().from(npPlugins);
1754
+ return rows.map(toState);
1755
+ }
1756
+ async function getPluginState(db, id) {
1757
+ const rows = await db.select().from(npPlugins).where(eq5(npPlugins.id, id)).limit(1);
1758
+ return rows[0] ? toState(rows[0]) : null;
1759
+ }
1760
+ async function syncPluginRegistrations(db, pluginIds) {
1761
+ if (pluginIds.length === 0) return;
1762
+ const now = /* @__PURE__ */ new Date();
1763
+ await db.insert(npPlugins).values(
1764
+ pluginIds.map((id) => ({
1765
+ id,
1766
+ enabled: true,
1767
+ installedAt: now,
1768
+ updatedAt: now
1769
+ }))
1770
+ ).onConflictDoNothing({ target: npPlugins.id });
1771
+ }
1772
+ async function updatePluginState(db, id, patch) {
1773
+ const values = {
1774
+ updatedAt: /* @__PURE__ */ new Date()
1775
+ };
1776
+ if (patch.enabled !== void 0) {
1777
+ values.enabled = patch.enabled;
1778
+ }
1779
+ const rows = await db.update(npPlugins).set(values).where(eq5(npPlugins.id, id)).returning();
1780
+ if (patch.enabled !== void 0) {
1781
+ invalidatePluginEnabled(id);
1782
+ }
1783
+ return rows[0] ? toState(rows[0]) : null;
1784
+ }
1785
+ export {
1786
+ ARGON2_OPTIONS,
1787
+ DEFAULT_COMMUNITY_SETTINGS,
1788
+ DEFAULT_IMAGE_SIZES,
1789
+ DEFAULT_JOB_LOG_RETENTION_MS,
1790
+ DEFAULT_REACTION_KINDS,
1791
+ DEFAULT_SITE_SEO_SETTINGS,
1792
+ DEFAULT_THEME,
1793
+ InMemoryRateLimiter,
1794
+ LocalStorageAdapter,
1795
+ MENTION_HANDLE_RE,
1796
+ NP_DEFAULT_SITE_ID,
1797
+ NP_GLOBAL_PLUGIN_SITE_ID,
1798
+ NoopEmailAdapter,
1799
+ NpAuthError,
1800
+ NpConflictError,
1801
+ NpError,
1802
+ NpForbiddenError,
1803
+ NpNotFoundError,
1804
+ NpRateLimitError,
1805
+ NpSiteContextMissingError,
1806
+ NpValidationError,
1807
+ PAUSE_SYNC_INTERVAL_MS,
1808
+ PgBossAdapter,
1809
+ ROLE_HIERARCHY,
1810
+ S3StorageAdapter,
1811
+ SmtpEmailAdapter,
1812
+ WORKER_HEARTBEAT_INTERVAL_MS,
1813
+ WORKER_STALE_THRESHOLD_MS,
1814
+ activeThemeContributesSeo,
1815
+ addReaction,
1816
+ addStrings,
1817
+ applyReputation,
1818
+ assertNotBanned,
1819
+ assertOwnsNotification,
1820
+ assertReactableExists,
1821
+ authenticated,
1822
+ autosaveRevision,
1823
+ buildArticleJsonLd,
1824
+ buildAtomFeed,
1825
+ buildDigestEmail,
1826
+ buildDiscussionForumPostingJsonLd,
1827
+ buildInviteEmail,
1828
+ buildPageMetadata,
1829
+ buildPersonJsonLd,
1830
+ buildResetEmail,
1831
+ buildSearchVector,
1832
+ buildSearchVectorParts,
1833
+ buildSitemap,
1834
+ buildWebSiteJsonLd,
1835
+ buildWeightedSearchVectorSql,
1836
+ buildZodSchema,
1837
+ can,
1838
+ checkNexpressCompat,
1839
+ checkThemeRequirements,
1840
+ cleanupDeletedMedia,
1841
+ clearCustomRoutes,
1842
+ clearStringOverrideCacheForSite,
1843
+ collectionConfigSchema,
1844
+ compareSemver,
1845
+ configureBuiltinJobContext,
1846
+ consoleLogger,
1847
+ consumeMemberEmailVerifyToken,
1848
+ consumeMemberPasswordReset,
1849
+ consumePasswordResetToken,
1850
+ countAliveWorkers,
1851
+ countJobLogs,
1852
+ countReactions,
1853
+ createComment,
1854
+ createDbConnection,
1855
+ createMemberDocument,
1856
+ createMemberEmailVerifyToken,
1857
+ createNotification,
1858
+ createPasswordResetToken,
1859
+ createSite,
1860
+ createStorageAdapter,
1861
+ createTranslation,
1862
+ defineCollection,
1863
+ defineConfig,
1864
+ deleteComment,
1865
+ deleteDocument,
1866
+ deleteMedia,
1867
+ deleteMemberDocument,
1868
+ deleteSite,
1869
+ deleteStringOverride,
1870
+ dispatchPluginAction,
1871
+ enqueueJob,
1872
+ ensureDefaultSite,
1873
+ extractErrorComponent,
1874
+ extractMediaIds,
1875
+ extractMembersNotFoundComponent,
1876
+ extractMentionHandles,
1877
+ extractMentionHandlesFromDocData,
1878
+ extractMentionHandlesFromRichText,
1879
+ extractNotFoundComponent,
1880
+ extractSeoHooks,
1881
+ fanOutMentionNotifications,
1882
+ fileReport,
1883
+ findDocuments,
1884
+ findPosts,
1885
+ findSlugRedirect,
1886
+ findTranslations,
1887
+ follow,
1888
+ formatDate,
1889
+ formatNumber,
1890
+ formatRelativeTime,
1891
+ fromArctic,
1892
+ generateDocumentsModule,
1893
+ generateDrizzleSchema,
1894
+ generateTypeScript,
1895
+ getActiveTheme,
1896
+ getActiveThemeError,
1897
+ getActiveThemeId,
1898
+ getActiveThemeMembersNotFound,
1899
+ getActiveThemeNavLocations,
1900
+ getActiveThemeNotFound,
1901
+ getActiveThemeSeoHooks,
1902
+ getAllCollectionSlugs,
1903
+ getAllJobHandlers,
1904
+ getAllPageSlugs,
1905
+ getAllPluginIds,
1906
+ getAllStrings,
1907
+ getCollectionConfig,
1908
+ getCollectionRegistration,
1909
+ getCollectionTable,
1910
+ getCollectionTabsForSlug,
1911
+ getCollectionZodSchema,
1912
+ getCommunityRole,
1913
+ getCommunitySettings,
1914
+ getCurrentJobId,
1915
+ getCurrentLocale,
1916
+ getCurrentSiteId,
1917
+ getCustomRoutes,
1918
+ getDashboardWidgetsFromPlugins,
1919
+ getDb,
1920
+ getDefaultSite,
1921
+ getDocumentById,
1922
+ getEmailAdapter,
1923
+ getErrorReporter,
1924
+ getFrameworkVersion,
1925
+ getI18nConfig,
1926
+ getJobHandler,
1927
+ getJobQueue,
1928
+ getJobsPauseState,
1929
+ getLocaleDirection,
1930
+ getLogger,
1931
+ getMediaById,
1932
+ getMediaUrl,
1933
+ getMemberFromTokenPayload,
1934
+ getMemberNotificationPrefs,
1935
+ getMemberProfile,
1936
+ getMemberProfiles,
1937
+ getMembership,
1938
+ getMutedTargetIds,
1939
+ getNavigation,
1940
+ getOAuthProvider,
1941
+ getOptionalJobQueue,
1942
+ getOptionalRateLimiter,
1943
+ getPageBySlug,
1944
+ getPluginAdminExtension,
1945
+ getPluginConfig,
1946
+ getPluginConfigWithStatus,
1947
+ getPluginPageRoutes,
1948
+ getPluginRegistration,
1949
+ getPluginRoutes,
1950
+ getPluginState,
1951
+ getPluginTemplatesForCollection,
1952
+ getPostBySlug,
1953
+ getProfanityAdapter,
1954
+ getRateLimiter,
1955
+ getRegisteredPluginSchedules,
1956
+ getRegisteredThemes,
1957
+ getReputationAdapter,
1958
+ getRevision,
1959
+ getScopedLogger,
1960
+ getSearchAdapter,
1961
+ getSetting,
1962
+ getSiteByHostname,
1963
+ getSiteById,
1964
+ getSiteSeoSettings,
1965
+ getSiteUsageSummary,
1966
+ getSpamAdapter,
1967
+ getStorageAdapter,
1968
+ getStringOverride,
1969
+ getStringOverridesForSite,
1970
+ getStrings,
1971
+ getTheme,
1972
+ getThemeById,
1973
+ getThemeSettings,
1974
+ getThemeSettingsWithStatus,
1975
+ getThemeTemplateSummaries,
1976
+ getTranslationProgress,
1977
+ grantMemberRole,
1978
+ grantSiteMembership,
1979
+ hasRoleOnSite,
1980
+ hashPassword,
1981
+ hideComment,
1982
+ introspectThemeSettingsSchema,
1983
+ invalidateAllMemberSessions,
1984
+ invalidateAllSessions,
1985
+ invalidatePluginEnabled,
1986
+ isAdmin,
1987
+ isEditorOrAbove,
1988
+ isFollowing,
1989
+ isMuted,
1990
+ isNotificationKindEnabled,
1991
+ isOwnerOrAdmin,
1992
+ isPluginEnabled,
1993
+ isSuperAdmin,
1994
+ isTokenVerificationError,
1995
+ issueBan,
1996
+ issueOAuthState,
1997
+ listAuditEvents,
1998
+ listBansForMember,
1999
+ listComments,
2000
+ listCommunityRoles,
2001
+ listFollowing,
2002
+ listJobLogs,
2003
+ listMedia,
2004
+ listMemberIdentities,
2005
+ listMemberReactions,
2006
+ listMemberRoleGrants,
2007
+ listMembershipsForUser,
2008
+ listMutes,
2009
+ listNotificationKinds,
2010
+ listNotifications,
2011
+ listOAuthProviders,
2012
+ listPendingMemberDocs,
2013
+ listPluginStates,
2014
+ listReports,
2015
+ listRevisions,
2016
+ listSiteMemberships,
2017
+ listSites,
2018
+ listStringOverridesForSite,
2019
+ listUserIdentities,
2020
+ listWorkerHealth,
2021
+ loadPlugins,
2022
+ loadStringOverridesForSite,
2023
+ markAllNotificationsRead,
2024
+ markNotificationsRead,
2025
+ markWorkerStopped,
2026
+ memberCan,
2027
+ muteMember,
2028
+ noopErrorReporter,
2029
+ npAuditEvents,
2030
+ npBanKindEnum,
2031
+ npBanScopeEnum,
2032
+ npBans,
2033
+ npCommentStatusEnum,
2034
+ npComments,
2035
+ npConfigSchema,
2036
+ npFollows,
2037
+ npJobLogs,
2038
+ npMedia,
2039
+ npMediaFolders,
2040
+ npMediaFoldersRelations,
2041
+ npMediaRefs,
2042
+ npMediaRefsRelations,
2043
+ npMediaRelations,
2044
+ npMediaStatusEnum,
2045
+ npMemberIdentities,
2046
+ npMemberMutes,
2047
+ npMemberRoleScopeEnum,
2048
+ npMemberRoles,
2049
+ npMemberSessions,
2050
+ npMemberStatusEnum,
2051
+ npMembers,
2052
+ npNavigation,
2053
+ npNavigationRelations,
2054
+ npNotifications,
2055
+ npPasswordResetPurposeEnum,
2056
+ npPluginStorage,
2057
+ npPlugins,
2058
+ npReactions,
2059
+ npReports,
2060
+ npRevisionStatusEnum,
2061
+ npRevisions,
2062
+ npRevisionsRelations,
2063
+ npSessions,
2064
+ npSessionsRelations,
2065
+ npSettings,
2066
+ npSettingsRelations,
2067
+ npSiteMemberships,
2068
+ npSites,
2069
+ npSlugHistory,
2070
+ npStringOverrides,
2071
+ npUserOAuthIdentities,
2072
+ npUserRoleEnum,
2073
+ npUsers,
2074
+ npUsersRelations,
2075
+ npWorkerHeartbeats,
2076
+ pluginConfigCacheTag,
2077
+ principalCan,
2078
+ processImage,
2079
+ processMediaImage,
2080
+ promoteMemberDocument,
2081
+ pruneJobLogsOlderThan,
2082
+ publishScheduledDocuments,
2083
+ purgeMemberContent,
2084
+ purgeStaleWorkers,
2085
+ recordAuditEvent,
2086
+ recordDigestSent,
2087
+ recordHeartbeat,
2088
+ recordJobLog,
2089
+ registerBuiltinHandlers,
2090
+ registerCollection,
2091
+ registerCommunityRole,
2092
+ registerCustomRoute,
2093
+ registerJobHandler,
2094
+ registerNotificationKind,
2095
+ registerOAuthProvider,
2096
+ registerPluginTemplates,
2097
+ registerThemes,
2098
+ reindexCollection,
2099
+ removeReaction,
2100
+ renderAtomFeed,
2101
+ renderCommentMarkdown,
2102
+ renderSitemapIndexXml,
2103
+ renderSitemapXml,
2104
+ reportError,
2105
+ requestMemberPasswordReset,
2106
+ requestPasswordReset,
2107
+ resetCommunityRoles,
2108
+ resetCurrentSiteResolver,
2109
+ resetEmailAdapter,
2110
+ resetErrorReporter,
2111
+ resetI18nConfig,
2112
+ resetIntlFormatterCache,
2113
+ resetLogger,
2114
+ resetOAuthProviders,
2115
+ resetPluginTemplates,
2116
+ resetPlugins,
2117
+ resetProfanityAdapter,
2118
+ resetReputationAdapter,
2119
+ resetSearchAdapter,
2120
+ resetSpamAdapter,
2121
+ resetStringOverrideCache,
2122
+ resetStrings,
2123
+ resetThemes,
2124
+ resetTranslationCache,
2125
+ resolveLocale,
2126
+ resolveMemberOAuthLogin,
2127
+ resolveMentionedMembers,
2128
+ resolveOAuthLogin,
2129
+ resolveReport,
2130
+ resolveSiteForHostname,
2131
+ resolveTemplateComponent,
2132
+ resolveUserRoleOnSite,
2133
+ restoreComment,
2134
+ restoreRevision,
2135
+ revokeBan,
2136
+ revokeMemberIdentity,
2137
+ revokeMemberRole,
2138
+ revokeSiteMembership,
2139
+ revokeUserIdentity,
2140
+ runDigestSweep,
2141
+ runHook,
2142
+ runHookAndCollect,
2143
+ runInJobContext,
2144
+ runPluginScheduledTask,
2145
+ sanitizeTokenValue,
2146
+ saveDocument,
2147
+ schedulePluginTask,
2148
+ searchCollections,
2149
+ setActiveThemeId,
2150
+ setCurrentSiteResolver,
2151
+ setDb,
2152
+ setEmailAdapter,
2153
+ setErrorReporter,
2154
+ setI18nConfig,
2155
+ setJobQueue,
2156
+ setJobsPauseState,
2157
+ setLogger,
2158
+ setMemberNotificationPrefs,
2159
+ setPluginConfig,
2160
+ setProfanityAdapter,
2161
+ setRateLimiter,
2162
+ setReputationAdapter,
2163
+ setSearchAdapter,
2164
+ setSpamAdapter,
2165
+ setStorageAdapter,
2166
+ setStringOverride,
2167
+ setStrings,
2168
+ setSuperAdmin,
2169
+ setThemeSettings,
2170
+ sha256,
2171
+ signMemberToken,
2172
+ signToken,
2173
+ staffDeleteComment,
2174
+ staffHideComment,
2175
+ staffRestoreComment,
2176
+ startProducer,
2177
+ startWorker,
2178
+ stopProducer,
2179
+ stopWorker,
2180
+ syncPluginRegistrations,
2181
+ t,
2182
+ tSync,
2183
+ unfollow,
2184
+ unmuteMember,
2185
+ unreadNotificationCount,
2186
+ unresolvedReportCount,
2187
+ updateComment,
2188
+ updateCommunitySettings,
2189
+ updateMemberDocument,
2190
+ updatePluginState,
2191
+ updateSite,
2192
+ uploadMedia,
2193
+ validateCommunitySettingsPatch,
2194
+ validateSeoSettingsPatch,
2195
+ verifyCsrf,
2196
+ verifyMemberToken,
2197
+ verifyOAuthState,
2198
+ verifyPassword,
2199
+ verifyStartupSafety,
2200
+ verifyToken,
2201
+ verifyTokenFull,
2202
+ withCurrentSite,
2203
+ withMemberWrite
2204
+ };
2205
+ //# sourceMappingURL=index.js.map