@meith/web 0.16.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 (511) hide show
  1. package/LICENSE.md +165 -0
  2. package/app/(auth)/layout.tsx +6 -0
  3. package/app/(auth)/login/page.tsx +106 -0
  4. package/app/(auth)/login/verify/page.tsx +55 -0
  5. package/app/(auth)/register/page.tsx +83 -0
  6. package/app/(auth)/reset/confirm/page.tsx +45 -0
  7. package/app/(auth)/reset/page.tsx +22 -0
  8. package/app/(auth)/verify/page.tsx +44 -0
  9. package/app/(auth)/verify/resend/page.tsx +51 -0
  10. package/app/(board)/[slug]/feed.xml/route.ts +48 -0
  11. package/app/(board)/[slug]/new/page.tsx +112 -0
  12. package/app/(board)/[slug]/page.tsx +403 -0
  13. package/app/(board)/discover/[view]/page.tsx +115 -0
  14. package/app/(board)/discover/page.tsx +5 -0
  15. package/app/(board)/layout.tsx +22 -0
  16. package/app/(board)/member/[id]/page.tsx +187 -0
  17. package/app/(board)/member/[id]/reputation/page.tsx +195 -0
  18. package/app/(board)/member/by-name/[name]/page.tsx +32 -0
  19. package/app/(board)/messages/[id]/page.tsx +103 -0
  20. package/app/(board)/messages/compose/page.tsx +60 -0
  21. package/app/(board)/messages/layout.tsx +5 -0
  22. package/app/(board)/messages/page.tsx +179 -0
  23. package/app/(board)/modcp/forums/page.tsx +59 -0
  24. package/app/(board)/modcp/ip/page.tsx +158 -0
  25. package/app/(board)/modcp/layout.tsx +5 -0
  26. package/app/(board)/modcp/log/page.tsx +98 -0
  27. package/app/(board)/modcp/page.tsx +112 -0
  28. package/app/(board)/moderation/layout.tsx +5 -0
  29. package/app/(board)/moderation/page.tsx +111 -0
  30. package/app/(board)/moderation/reports/page.tsx +193 -0
  31. package/app/(board)/moderation/warn/page.tsx +158 -0
  32. package/app/(board)/notifications/layout.tsx +5 -0
  33. package/app/(board)/notifications/page.tsx +144 -0
  34. package/app/(board)/notifications/preferences/page.tsx +65 -0
  35. package/app/(board)/online/page.tsx +119 -0
  36. package/app/(board)/page.tsx +195 -0
  37. package/app/(board)/plugins/[key]/[[...path]]/page.tsx +72 -0
  38. package/app/(board)/privacy/page.tsx +12 -0
  39. package/app/(board)/report/page.tsx +71 -0
  40. package/app/(board)/rules/page.tsx +12 -0
  41. package/app/(board)/search/[token]/page.tsx +130 -0
  42. package/app/(board)/search/page.tsx +289 -0
  43. package/app/(board)/stats/page.tsx +202 -0
  44. package/app/(board)/subscriptions/layout.tsx +5 -0
  45. package/app/(board)/subscriptions/page.tsx +142 -0
  46. package/app/(board)/terms/page.tsx +12 -0
  47. package/app/(board)/thread/[slug]/edit/page.tsx +107 -0
  48. package/app/(board)/thread/[slug]/feed.xml/route.ts +42 -0
  49. package/app/(board)/thread/[slug]/page.tsx +707 -0
  50. package/app/(board)/thread/[slug]/poll/page.tsx +41 -0
  51. package/app/(board)/thread/[slug]/post/[postId]/history/page.tsx +160 -0
  52. package/app/(board)/thread/[slug]/reply/page.tsx +136 -0
  53. package/app/(board)/unsubscribe/page.tsx +73 -0
  54. package/app/(board)/usercp/avatar/page.tsx +56 -0
  55. package/app/(board)/usercp/contacts/page.tsx +141 -0
  56. package/app/(board)/usercp/email/confirm/page.tsx +52 -0
  57. package/app/(board)/usercp/layout.tsx +23 -0
  58. package/app/(board)/usercp/options/page.tsx +56 -0
  59. package/app/(board)/usercp/page.tsx +71 -0
  60. package/app/(board)/usercp/profile/page.tsx +81 -0
  61. package/app/(board)/usercp/security/page.tsx +238 -0
  62. package/app/(board)/usercp/security/verify/page.tsx +92 -0
  63. package/app/(board)/usercp/signature/page.tsx +67 -0
  64. package/app/admin/antispam/page.tsx +155 -0
  65. package/app/admin/api/marketplace/screenshot/route.ts +68 -0
  66. package/app/admin/api/plugins/[key]/[...path]/route.ts +27 -0
  67. package/app/admin/api-tokens/page.tsx +129 -0
  68. package/app/admin/content/announcements/page.tsx +110 -0
  69. package/app/admin/content/attachments/page.tsx +199 -0
  70. package/app/admin/content/navigation/page.tsx +123 -0
  71. package/app/admin/content/page.tsx +170 -0
  72. package/app/admin/forums/[id]/page.tsx +96 -0
  73. package/app/admin/forums/[id]/permissions/page.tsx +108 -0
  74. package/app/admin/forums/page.tsx +45 -0
  75. package/app/admin/groups/[id]/page.tsx +133 -0
  76. package/app/admin/groups/memberships/page.tsx +56 -0
  77. package/app/admin/groups/page.tsx +104 -0
  78. package/app/admin/groups/promotions/page.tsx +143 -0
  79. package/app/admin/layout.tsx +86 -0
  80. package/app/admin/log/page.tsx +116 -0
  81. package/app/admin/page.tsx +206 -0
  82. package/app/admin/plugins/[key]/[[...path]]/page.tsx +276 -0
  83. package/app/admin/plugins/browse/page.tsx +70 -0
  84. package/app/admin/plugins/page.tsx +165 -0
  85. package/app/admin/security/page.tsx +124 -0
  86. package/app/admin/settings/page.tsx +190 -0
  87. package/app/admin/system/page.tsx +303 -0
  88. package/app/admin/themes/[key]/page.tsx +110 -0
  89. package/app/admin/themes/browse/page.tsx +70 -0
  90. package/app/admin/themes/page.tsx +163 -0
  91. package/app/admin/users/[id]/merge/page.tsx +136 -0
  92. package/app/admin/users/[id]/page.tsx +208 -0
  93. package/app/admin/users/mail/page.tsx +68 -0
  94. package/app/admin/users/page.tsx +260 -0
  95. package/app/admin/users/prune/page.tsx +186 -0
  96. package/app/api/health/route.ts +11 -0
  97. package/app/api/metrics/route.ts +66 -0
  98. package/app/api/plugins/[key]/[...path]/route.ts +27 -0
  99. package/app/api/read/all/route.ts +15 -0
  100. package/app/api/read/forum/[id]/route.ts +29 -0
  101. package/app/api/read/thread/[id]/route.ts +40 -0
  102. package/app/api/ready/route.ts +63 -0
  103. package/app/api/system/tick/route.ts +77 -0
  104. package/app/api/v1/[...path]/route.ts +208 -0
  105. package/app/api/v1/openapi.json/route.ts +12 -0
  106. package/app/apple-icon.ts +11 -0
  107. package/app/atom.xml/route.ts +7 -0
  108. package/app/attachment/[id]/route.ts +10 -0
  109. package/app/attachment/[id]/thumb/route.ts +10 -0
  110. package/app/auth/passkey/options/route.ts +145 -0
  111. package/app/auth/passkey/verify/route.ts +241 -0
  112. package/app/auth/resume/route.ts +55 -0
  113. package/app/auth/sso/[provider]/callback/route.ts +173 -0
  114. package/app/auth/sso/[provider]/go/route.ts +57 -0
  115. package/app/auth/sso/[provider]/route.ts +105 -0
  116. package/app/avatar/[id]/route.ts +31 -0
  117. package/app/brand/icon-192.png/route.ts +7 -0
  118. package/app/brand/icon-512.png/route.ts +7 -0
  119. package/app/brand/icon-maskable.png/route.ts +7 -0
  120. package/app/demo/stripe/[[...path]]/route.ts +27 -0
  121. package/app/error.tsx +15 -0
  122. package/app/feed.xml/route.ts +7 -0
  123. package/app/forumdisplay.php/page.tsx +11 -0
  124. package/app/group/[id]/badge/[scheme]/route.ts +26 -0
  125. package/app/icon.ts +13 -0
  126. package/app/install/page.tsx +221 -0
  127. package/app/jump/page.tsx +28 -0
  128. package/app/layout.tsx +124 -0
  129. package/app/logo/[scheme]/route.ts +24 -0
  130. package/app/manifest.ts +43 -0
  131. package/app/member.php/page.tsx +11 -0
  132. package/app/memberlist.php/page.tsx +11 -0
  133. package/app/not-found.tsx +14 -0
  134. package/app/opengraph-image.ts +11 -0
  135. package/app/redirect/page.tsx +44 -0
  136. package/app/robots.txt/route.ts +35 -0
  137. package/app/showthread.php/page.tsx +11 -0
  138. package/app/sitemap/[page]/route.ts +64 -0
  139. package/app/sitemap.xml/route.ts +31 -0
  140. package/app/twitter-image.ts +11 -0
  141. package/app/viewforum.php/page.tsx +11 -0
  142. package/app/viewtopic.php/page.tsx +11 -0
  143. package/bin/forum-web.mjs +241 -0
  144. package/components.json +21 -0
  145. package/instrumentation.ts +18 -0
  146. package/next.config.mjs +182 -0
  147. package/package.json +99 -0
  148. package/postcss.config.mjs +7 -0
  149. package/proxy.ts +160 -0
  150. package/src/components/account/active-sessions.tsx +87 -0
  151. package/src/components/account/avatar-form.tsx +119 -0
  152. package/src/components/account/credential-proof-form.tsx +76 -0
  153. package/src/components/account/logout-form.tsx +14 -0
  154. package/src/components/account/notification-forms.tsx +157 -0
  155. package/src/components/account/passkey-enrol.tsx +81 -0
  156. package/src/components/account/passkey-proof-button.tsx +47 -0
  157. package/src/components/account/push-device-form.tsx +193 -0
  158. package/src/components/account/relation-forms.tsx +69 -0
  159. package/src/components/account/reputation-forms.tsx +124 -0
  160. package/src/components/account/security-activity.tsx +46 -0
  161. package/src/components/account/sign-in-methods.tsx +166 -0
  162. package/src/components/account/subscription-forms.tsx +151 -0
  163. package/src/components/account/two-factor-forms.tsx +226 -0
  164. package/src/components/account/usercp-forms.tsx +387 -0
  165. package/src/components/account/usercp-nav.tsx +14 -0
  166. package/src/components/account/usercp-shell.tsx +34 -0
  167. package/src/components/admin/admin-forms.tsx +92 -0
  168. package/src/components/admin/admin-nav.tsx +52 -0
  169. package/src/components/admin/admin-undo.tsx +32 -0
  170. package/src/components/admin/api-token-forms.tsx +89 -0
  171. package/src/components/admin/badge-forms.tsx +97 -0
  172. package/src/components/admin/branding-forms.tsx +102 -0
  173. package/src/components/admin/content-forms.tsx +712 -0
  174. package/src/components/admin/form-bits.tsx +11 -0
  175. package/src/components/admin/forum-forms.tsx +524 -0
  176. package/src/components/admin/forum-tree.tsx +454 -0
  177. package/src/components/admin/group-forms.tsx +646 -0
  178. package/src/components/admin/mail-test-card.tsx +90 -0
  179. package/src/components/admin/marketplace-forms.tsx +30 -0
  180. package/src/components/admin/marketplace-listing.tsx +123 -0
  181. package/src/components/admin/navigation-forms.tsx +229 -0
  182. package/src/components/admin/navigation-tree.tsx +442 -0
  183. package/src/components/admin/oklch-picker.tsx +180 -0
  184. package/src/components/admin/plugin-forms.tsx +225 -0
  185. package/src/components/admin/settings-form.tsx +148 -0
  186. package/src/components/admin/system-forms.tsx +169 -0
  187. package/src/components/admin/theme-changes.tsx +354 -0
  188. package/src/components/admin/theme-forms.tsx +636 -0
  189. package/src/components/admin/theme-palette.tsx +119 -0
  190. package/src/components/admin/theme-preview.tsx +461 -0
  191. package/src/components/admin/user-bulk-toolbar.tsx +99 -0
  192. package/src/components/admin/user-forms.tsx +488 -0
  193. package/src/components/auth/auth-page.tsx +45 -0
  194. package/src/components/auth/form-controls.tsx +117 -0
  195. package/src/components/auth/login-form.tsx +47 -0
  196. package/src/components/auth/passkey-client.ts +171 -0
  197. package/src/components/auth/passkey-second-factor.tsx +69 -0
  198. package/src/components/auth/passkey-sign-in.tsx +61 -0
  199. package/src/components/auth/register-form.tsx +136 -0
  200. package/src/components/auth/resend-verification-form.tsx +34 -0
  201. package/src/components/auth/reset-confirm-form.tsx +43 -0
  202. package/src/components/auth/reset-request-form.tsx +35 -0
  203. package/src/components/auth/second-factor-form.tsx +51 -0
  204. package/src/components/auth/sso-buttons.tsx +47 -0
  205. package/src/components/board/live-region.tsx +74 -0
  206. package/src/components/board/search-off-notice.tsx +18 -0
  207. package/src/components/board/section-page.tsx +114 -0
  208. package/src/components/content/attachment-field.tsx +51 -0
  209. package/src/components/content/composer-field.ts +31 -0
  210. package/src/components/content/composer-ids.ts +6 -0
  211. package/src/components/content/composer-intents.tsx +27 -0
  212. package/src/components/content/composer-recovery.tsx +215 -0
  213. package/src/components/content/edit-post-form.tsx +121 -0
  214. package/src/components/content/markdown-editor.tsx +590 -0
  215. package/src/components/content/markdown-syntax.ts +53 -0
  216. package/src/components/content/mention-token.ts +23 -0
  217. package/src/components/content/multiquote-button.tsx +32 -0
  218. package/src/components/content/multiquote-selection.tsx +105 -0
  219. package/src/components/content/multiquote.ts +125 -0
  220. package/src/components/content/new-thread-form.tsx +169 -0
  221. package/src/components/content/poll-edit-form.tsx +96 -0
  222. package/src/components/content/poll.tsx +89 -0
  223. package/src/components/content/quote-in-place.tsx +51 -0
  224. package/src/components/content/reply-form.tsx +113 -0
  225. package/src/components/content/thanks-button.tsx +65 -0
  226. package/src/components/content/thread-rating.tsx +143 -0
  227. package/src/components/install/install-form.tsx +497 -0
  228. package/src/components/legal/legal-document.tsx +22 -0
  229. package/src/components/messages/message-forms.tsx +152 -0
  230. package/src/components/moderation/inline-moderation-form.tsx +158 -0
  231. package/src/components/moderation/modcp-nav.tsx +15 -0
  232. package/src/components/moderation/modcp-shell.tsx +41 -0
  233. package/src/components/moderation/queue-form.tsx +96 -0
  234. package/src/components/moderation/report-forms.tsx +120 -0
  235. package/src/components/moderation/signature-lock-form.tsx +83 -0
  236. package/src/components/moderation/thread-surgery-form.tsx +96 -0
  237. package/src/components/moderation/thread-tools-form.tsx +137 -0
  238. package/src/components/moderation/warning-forms.tsx +125 -0
  239. package/src/components/profile/custom-field.tsx +79 -0
  240. package/src/components/shell/appearance-icons.tsx +35 -0
  241. package/src/components/shell/board-notice.tsx +21 -0
  242. package/src/components/shell/copy-record.ts +20 -0
  243. package/src/components/shell/copy.tsx +17 -0
  244. package/src/components/shell/crash-notice.tsx +86 -0
  245. package/src/components/shell/demo-banner.tsx +49 -0
  246. package/src/components/shell/group-name-style.tsx +6 -0
  247. package/src/components/shell/measure.ts +1 -0
  248. package/src/components/shell/notification-menu.tsx +361 -0
  249. package/src/components/shell/offline-notice.tsx +29 -0
  250. package/src/components/shell/onboarding-banner.tsx +39 -0
  251. package/src/components/shell/page-shell.tsx +167 -0
  252. package/src/components/shell/panel-list.tsx +95 -0
  253. package/src/components/shell/panel-nav.tsx +40 -0
  254. package/src/components/shell/panel-overview.tsx +81 -0
  255. package/src/components/shell/panel-page.tsx +96 -0
  256. package/src/components/shell/panel-pagination.tsx +28 -0
  257. package/src/components/shell/panel-shell.tsx +31 -0
  258. package/src/components/shell/theme-runtime-style.tsx +6 -0
  259. package/src/components/shell/theme-switcher.tsx +97 -0
  260. package/src/components/shell/timezone-probe.tsx +45 -0
  261. package/src/components/shell/view-tabs.tsx +60 -0
  262. package/src/config.ts +13 -0
  263. package/src/server/absent-services.ts +29 -0
  264. package/src/server/admin-actions.ts +171 -0
  265. package/src/server/admin-settings-actions.ts +83 -0
  266. package/src/server/admin-undo-actions.ts +70 -0
  267. package/src/server/admin-undo.ts +75 -0
  268. package/src/server/admin.ts +112 -0
  269. package/src/server/announcements.ts +82 -0
  270. package/src/server/antispam.ts +310 -0
  271. package/src/server/api/content.ts +486 -0
  272. package/src/server/api/http.ts +119 -0
  273. package/src/server/api/members.ts +109 -0
  274. package/src/server/api/messages.ts +113 -0
  275. package/src/server/api/registry.ts +30 -0
  276. package/src/server/api/search.ts +98 -0
  277. package/src/server/api/subscriptions.ts +106 -0
  278. package/src/server/api-auth.ts +66 -0
  279. package/src/server/api-token-actions.ts +85 -0
  280. package/src/server/api-tokens-admin.ts +95 -0
  281. package/src/server/appearance-actions.ts +39 -0
  282. package/src/server/attachment-download.ts +43 -0
  283. package/src/server/attachment-embed.ts +63 -0
  284. package/src/server/attachment-upload-actions.ts +92 -0
  285. package/src/server/attachments.ts +257 -0
  286. package/src/server/auth-actions.ts +479 -0
  287. package/src/server/auth-config.ts +61 -0
  288. package/src/server/auth-events.ts +92 -0
  289. package/src/server/auth-form-state.ts +14 -0
  290. package/src/server/auth-mail.ts +104 -0
  291. package/src/server/avatars.ts +83 -0
  292. package/src/server/board-latest-actions.ts +7 -0
  293. package/src/server/board-latest.tsx +103 -0
  294. package/src/server/board-offline.ts +23 -0
  295. package/src/server/board-url.ts +14 -0
  296. package/src/server/brand-assets.ts +151 -0
  297. package/src/server/brand-mark.tsx +110 -0
  298. package/src/server/branding-actions.ts +53 -0
  299. package/src/server/branding.ts +101 -0
  300. package/src/server/cache-targets.ts +13 -0
  301. package/src/server/code-highlighting.ts +33 -0
  302. package/src/server/container.ts +402 -0
  303. package/src/server/content-actions.ts +459 -0
  304. package/src/server/content-admin-actions.ts +492 -0
  305. package/src/server/content-admin.ts +95 -0
  306. package/src/server/content-security-policy.ts +35 -0
  307. package/src/server/context.ts +32 -0
  308. package/src/server/cookies.ts +139 -0
  309. package/src/server/credential-proof-actions.ts +42 -0
  310. package/src/server/credential-proof.ts +35 -0
  311. package/src/server/current-location.ts +19 -0
  312. package/src/server/demo-stripe.ts +104 -0
  313. package/src/server/demo-uploads.ts +28 -0
  314. package/src/server/demo.ts +80 -0
  315. package/src/server/discovery.ts +104 -0
  316. package/src/server/embeds.ts +113 -0
  317. package/src/server/error-notice.tsx +41 -0
  318. package/src/server/federation-actions.ts +113 -0
  319. package/src/server/federation.ts +138 -0
  320. package/src/server/feed-builder.ts +72 -0
  321. package/src/server/feed-routes.ts +122 -0
  322. package/src/server/fixture-actor-source.ts +62 -0
  323. package/src/server/fixture-forum-repo.ts +59 -0
  324. package/src/server/fixture-member-profile-repo.ts +30 -0
  325. package/src/server/fixture-post-repo.ts +108 -0
  326. package/src/server/fixture-thread-repo.ts +98 -0
  327. package/src/server/form-state-reporter.ts +34 -0
  328. package/src/server/form-values.ts +23 -0
  329. package/src/server/forum-admin-actions.ts +353 -0
  330. package/src/server/forum-admin.ts +98 -0
  331. package/src/server/group-admin-actions.ts +341 -0
  332. package/src/server/group-admin.ts +98 -0
  333. package/src/server/group-badge-actions.ts +61 -0
  334. package/src/server/group-badge.ts +62 -0
  335. package/src/server/group-identity.ts +104 -0
  336. package/src/server/i18n-catalogs.ts +42 -0
  337. package/src/server/i18n.ts +69 -0
  338. package/src/server/image-upload.ts +109 -0
  339. package/src/server/inline-moderation-actions.ts +129 -0
  340. package/src/server/install-actions.ts +124 -0
  341. package/src/server/install.ts +281 -0
  342. package/src/server/legacy-redirect.ts +83 -0
  343. package/src/server/legal.ts +43 -0
  344. package/src/server/location-header.ts +37 -0
  345. package/src/server/mail-brand.ts +43 -0
  346. package/src/server/mail-health.ts +41 -0
  347. package/src/server/mail-send.ts +44 -0
  348. package/src/server/mail-test-actions.ts +67 -0
  349. package/src/server/mail-test.ts +56 -0
  350. package/src/server/markdown-pipeline.ts +31 -0
  351. package/src/server/marketplace-actions.ts +47 -0
  352. package/src/server/marketplace-admin.ts +260 -0
  353. package/src/server/mention-actions.ts +21 -0
  354. package/src/server/mention-search.ts +35 -0
  355. package/src/server/message-actions.ts +110 -0
  356. package/src/server/messages.ts +141 -0
  357. package/src/server/modcp.ts +125 -0
  358. package/src/server/moderation-actions.ts +165 -0
  359. package/src/server/navigation-admin-actions.ts +217 -0
  360. package/src/server/navigation.ts +112 -0
  361. package/src/server/nonce.ts +13 -0
  362. package/src/server/notification-actions.ts +84 -0
  363. package/src/server/notification-audience.ts +10 -0
  364. package/src/server/notification-menu-actions.ts +82 -0
  365. package/src/server/notification-menu.ts +96 -0
  366. package/src/server/notifications.ts +93 -0
  367. package/src/server/onboarding-actions.ts +27 -0
  368. package/src/server/onboarding.ts +89 -0
  369. package/src/server/page-metadata.ts +14 -0
  370. package/src/server/passkey-challenge.ts +42 -0
  371. package/src/server/plugin-admin-actions.ts +232 -0
  372. package/src/server/plugin-admin.ts +276 -0
  373. package/src/server/plugin-host.ts +143 -0
  374. package/src/server/plugin-pages.ts +192 -0
  375. package/src/server/plugin-panel.ts +49 -0
  376. package/src/server/plugin-routes.ts +298 -0
  377. package/src/server/plugin-view.tsx +58 -0
  378. package/src/server/poll-actions.ts +104 -0
  379. package/src/server/poll-scope.ts +52 -0
  380. package/src/server/post-notifications.ts +71 -0
  381. package/src/server/post-scope.ts +86 -0
  382. package/src/server/presence.ts +177 -0
  383. package/src/server/profile-fields.ts +112 -0
  384. package/src/server/push-actions.ts +113 -0
  385. package/src/server/push.ts +40 -0
  386. package/src/server/redirect-back.ts +15 -0
  387. package/src/server/registration.ts +7 -0
  388. package/src/server/relation-actions.ts +89 -0
  389. package/src/server/relations.ts +45 -0
  390. package/src/server/reply-core.ts +173 -0
  391. package/src/server/report-actions.ts +165 -0
  392. package/src/server/report-scope.ts +21 -0
  393. package/src/server/reputation-actions.ts +146 -0
  394. package/src/server/reputation-target.ts +49 -0
  395. package/src/server/reputation.ts +70 -0
  396. package/src/server/request-fingerprint.ts +65 -0
  397. package/src/server/safe-path.ts +16 -0
  398. package/src/server/same-origin.ts +45 -0
  399. package/src/server/search-page.ts +313 -0
  400. package/src/server/search.ts +45 -0
  401. package/src/server/secret-auth.ts +20 -0
  402. package/src/server/see-other.ts +11 -0
  403. package/src/server/seed-board.ts +417 -0
  404. package/src/server/session-actions.ts +78 -0
  405. package/src/server/session-cookies.ts +124 -0
  406. package/src/server/session-key.ts +17 -0
  407. package/src/server/settings.ts +47 -0
  408. package/src/server/signatures.ts +62 -0
  409. package/src/server/sso-handshake.ts +79 -0
  410. package/src/server/stats.ts +63 -0
  411. package/src/server/subscription-actions.ts +161 -0
  412. package/src/server/surgery-actions.ts +180 -0
  413. package/src/server/syndication.ts +77 -0
  414. package/src/server/system-admin-actions.ts +134 -0
  415. package/src/server/system-admin.ts +90 -0
  416. package/src/server/test-container.ts +114 -0
  417. package/src/server/theme-admin-actions.ts +242 -0
  418. package/src/server/theme-admin.ts +203 -0
  419. package/src/server/theme-runtime.ts +89 -0
  420. package/src/server/theme-style.ts +279 -0
  421. package/src/server/theme.ts +52 -0
  422. package/src/server/thread-core.ts +207 -0
  423. package/src/server/thread-rating-actions.ts +55 -0
  424. package/src/server/thread-tool-actions.ts +154 -0
  425. package/src/server/two-factor-actions.ts +178 -0
  426. package/src/server/two-factor.ts +86 -0
  427. package/src/server/upgrade-notice.ts +41 -0
  428. package/src/server/user-admin-actions.ts +572 -0
  429. package/src/server/user-admin.ts +165 -0
  430. package/src/server/usercp-actions.ts +263 -0
  431. package/src/server/usercp-mail.ts +120 -0
  432. package/src/server/viewer-preferences.ts +64 -0
  433. package/src/server/warning-actions.ts +122 -0
  434. package/src/styles/globals.css +969 -0
  435. package/src/theme/contract.fixture.ts +793 -0
  436. package/src/view/account-copy.ts +351 -0
  437. package/src/view/admin-content-copy.ts +66 -0
  438. package/src/view/admin-copy.ts +106 -0
  439. package/src/view/admin-forum-tree-copy.ts +40 -0
  440. package/src/view/admin-group-copy.ts +80 -0
  441. package/src/view/admin-log.ts +58 -0
  442. package/src/view/admin-nav.ts +164 -0
  443. package/src/view/admin-navigation-copy.ts +58 -0
  444. package/src/view/admin-panel-copy.ts +194 -0
  445. package/src/view/admin-settings.ts +173 -0
  446. package/src/view/admin-theme-copy.ts +229 -0
  447. package/src/view/admin-user-copy.ts +96 -0
  448. package/src/view/attachments.ts +51 -0
  449. package/src/view/auth-copy.ts +147 -0
  450. package/src/view/board-index.ts +167 -0
  451. package/src/view/board-latest.ts +101 -0
  452. package/src/view/breadcrumb.ts +50 -0
  453. package/src/view/contacts.ts +85 -0
  454. package/src/view/content-copy.ts +118 -0
  455. package/src/view/contrast.ts +286 -0
  456. package/src/view/copy.ts +101 -0
  457. package/src/view/count.ts +8 -0
  458. package/src/view/discovery-view.ts +74 -0
  459. package/src/view/editor-toolbar.ts +84 -0
  460. package/src/view/error-notice.ts +52 -0
  461. package/src/view/feed.ts +130 -0
  462. package/src/view/forum-cursor.ts +54 -0
  463. package/src/view/forum-display.ts +152 -0
  464. package/src/view/forum-jump.ts +60 -0
  465. package/src/view/forum-notice.ts +24 -0
  466. package/src/view/inline-moderation.ts +87 -0
  467. package/src/view/install-copy.ts +95 -0
  468. package/src/view/legal.ts +58 -0
  469. package/src/view/locale.ts +40 -0
  470. package/src/view/marketplace-panel.ts +51 -0
  471. package/src/view/member-identity.ts +23 -0
  472. package/src/view/member-profile.ts +65 -0
  473. package/src/view/messages.ts +222 -0
  474. package/src/view/metadata.ts +75 -0
  475. package/src/view/modcp-nav.ts +76 -0
  476. package/src/view/moderation-copy.ts +84 -0
  477. package/src/view/moderation-queue.ts +67 -0
  478. package/src/view/navigation-arrange.ts +188 -0
  479. package/src/view/navigation.ts +173 -0
  480. package/src/view/notification-menu.ts +202 -0
  481. package/src/view/notifications.ts +84 -0
  482. package/src/view/onboarding.ts +26 -0
  483. package/src/view/pager.ts +191 -0
  484. package/src/view/panel-nav.ts +203 -0
  485. package/src/view/plugin-panel.ts +42 -0
  486. package/src/view/post-form.ts +61 -0
  487. package/src/view/post-link.ts +29 -0
  488. package/src/view/presence.ts +99 -0
  489. package/src/view/promotion-rules.ts +52 -0
  490. package/src/view/redirect-notice.ts +21 -0
  491. package/src/view/reputation.ts +107 -0
  492. package/src/view/search-controls.ts +103 -0
  493. package/src/view/search-results.ts +291 -0
  494. package/src/view/security-activity.ts +73 -0
  495. package/src/view/setting-groups.ts +43 -0
  496. package/src/view/shell.ts +164 -0
  497. package/src/view/slug-id.ts +12 -0
  498. package/src/view/sso-hand-off.ts +44 -0
  499. package/src/view/sso-notices.ts +48 -0
  500. package/src/view/subscriptions.ts +76 -0
  501. package/src/view/theme-draft.ts +167 -0
  502. package/src/view/theme-preference.ts +30 -0
  503. package/src/view/theme-tokens.ts +333 -0
  504. package/src/view/thread-view.ts +280 -0
  505. package/src/view/time.ts +31 -0
  506. package/src/view/timezone.ts +35 -0
  507. package/src/view/two-factor.ts +6 -0
  508. package/src/view/usercp-nav.ts +103 -0
  509. package/src/view/usercp.ts +196 -0
  510. package/src/view/warnings.ts +128 -0
  511. package/src/view/word-filter.ts +5 -0
@@ -0,0 +1,11 @@
1
+ import { renderBrandSocial } from '@/server/brand-mark'
2
+
3
+ export const dynamic = 'force-dynamic'
4
+
5
+ export const size = { width: 1200, height: 630 }
6
+
7
+ export const contentType = 'image/png'
8
+
9
+ export default function TwitterImage(): Promise<Response> {
10
+ return renderBrandSocial()
11
+ }
@@ -0,0 +1,11 @@
1
+ import { serveLegacyUrl } from '@/server/legacy-redirect'
2
+
3
+ export const dynamic = 'force-dynamic'
4
+
5
+ export default async function ViewforumPage({
6
+ searchParams,
7
+ }: {
8
+ searchParams: Promise<Record<string, string | string[] | undefined>>
9
+ }): Promise<never> {
10
+ return serveLegacyUrl('viewforum.php', await searchParams)
11
+ }
@@ -0,0 +1,11 @@
1
+ import { serveLegacyUrl } from '@/server/legacy-redirect'
2
+
3
+ export const dynamic = 'force-dynamic'
4
+
5
+ export default async function ViewtopicPage({
6
+ searchParams,
7
+ }: {
8
+ searchParams: Promise<Record<string, string | string[] | undefined>>
9
+ }): Promise<never> {
10
+ return serveLegacyUrl('viewtopic.php', await searchParams)
11
+ }
@@ -0,0 +1,241 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `forum-web` — the bin that makes `@meith/web` runnable as a plain
4
+ * dependency of an external board workspace (see docs/development.md,
5
+ * "Consuming the board from a workspace").
6
+ *
7
+ * A Next.js app is not consumable as a bare dependency: `next dev|build|start`
8
+ * need to run with the app's own directory as the project root, and the
9
+ * board-config seam (`@board/config` / `@board/plugins`, see
10
+ * docs/architecture.md) is a pair of tsconfig path aliases that inside this
11
+ * monorepo point at `apps/community`'s own files. Neither survives npm
12
+ * installing this package into somebody else's workspace unchanged.
13
+ *
14
+ * So on every invocation this bin:
15
+ *
16
+ * 1. Copies this package's own Next app sources into `.meith/app/` inside
17
+ * the invoking workspace (the current working directory) — gitignored,
18
+ * regenerated every time, never a merge target.
19
+ * 2. Writes `.meith/app/tsconfig.json`, a fresh tsconfig whose `paths`
20
+ * point `@board/config` and `@board/plugins` at *this workspace's own*
21
+ * `community.config.ts` / `community.plugins.ts` — the same seam, wired
22
+ * to a different pair of files. tsconfig `paths` are a compiler/bundler
23
+ * alias, not a package boundary, so nothing stops one from naming a
24
+ * path two directories up; that is the whole trick.
25
+ * 3. Runs `next dev|build|start` with `.meith/app/` as the project root.
26
+ *
27
+ * `.meith/app/` sits exactly two directories below the workspace root
28
+ * (`<root>/.meith/app`) on purpose: `next.config.mjs` (copied verbatim, see
29
+ * below) computes its own workspace root as two directories up from itself,
30
+ * so materializing at that exact depth keeps that computation correct
31
+ * without touching the file.
32
+ *
33
+ * This assumes a *hoisted* `node_modules` (npm, yarn classic, or pnpm with
34
+ * `node-linker=hoisted`) — see docs/development.md for why.
35
+ *
36
+ * `boards/stock` (docker/Dockerfile) is this bin's one *in-repo* consumer,
37
+ * and it has neither a hoisted `node_modules` nor a two-directories-up
38
+ * workspace root — it is a workspace member of this monorepo's own
39
+ * (non-hoisted) pnpm install, nested two directories deeper again. Two
40
+ * environment variables, set only by that workspace's own `build`/`dev`
41
+ * scripts, cover the difference without changing anything for a real
42
+ * external board, which never sets either: `FORUM_WORKSPACE_ROOT`
43
+ * (apps/community/next.config.mjs) points tracing at this repository's real
44
+ * root, and `FORUM_ALIASES_FROM` (`monorepoAliases()` below) carries this
45
+ * repository's own `@meith/*` tsconfig aliases into the generated tsconfig,
46
+ * since packages here resolve each other through those aliases rather than
47
+ * through real `dependencies` entries a hoisted `node_modules` would need.
48
+ */
49
+ import { spawn } from 'node:child_process'
50
+ import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
51
+ import { createRequire } from 'node:module'
52
+ import { dirname, join, relative, resolve, sep } from 'node:path'
53
+ import { fileURLToPath } from 'node:url'
54
+
55
+ const here = dirname(fileURLToPath(import.meta.url))
56
+ const packageRoot = join(here, '..')
57
+ const workspaceRoot = process.cwd()
58
+ const appDir = join(workspaceRoot, '.meith', 'app')
59
+
60
+ // `next dev|build` runs with `.meith/app` as its own cwd (see `run()` below),
61
+ // so a relative FORUM_WORKSPACE_ROOT / FORUM_ALIASES_FROM — the shape
62
+ // boards/stock/package.json's scripts write, relative to *this* process's
63
+ // own cwd (the board's own directory) — would resolve against the wrong
64
+ // directory if left for next.config.mjs to resolve itself. Rewriting them to
65
+ // absolute paths here, before spawning, means both env vars mean the same
66
+ // thing regardless of which process reads them.
67
+ for (const name of ['FORUM_WORKSPACE_ROOT', 'FORUM_ALIASES_FROM']) {
68
+ if (process.env[name]) process.env[name] = resolve(workspaceRoot, process.env[name])
69
+ }
70
+
71
+ // Files this package ships (see its `files` allowlist) that belong inside
72
+ // the materialized app. Board files (community.config.ts, board.plugins.json,
73
+ // community.plugins.ts) are never copied — they are read in place, from the
74
+ // workspace, through the generated tsconfig instead.
75
+ const APP_ENTRIES = [
76
+ 'app',
77
+ 'src',
78
+ 'next.config.mjs',
79
+ 'postcss.config.mjs',
80
+ 'components.json',
81
+ 'instrumentation.ts',
82
+ 'proxy.ts',
83
+ ]
84
+
85
+ function fail(message) {
86
+ console.error(`forum-web: ${message}`)
87
+ process.exit(1)
88
+ }
89
+
90
+ function toPosixRelative(from, to) {
91
+ const rel = relative(from, to).split(sep).join('/')
92
+ return rel.startsWith('.') ? rel : `./${rel}`
93
+ }
94
+
95
+ /**
96
+ * A board outside this monorepo has a hoisted `node_modules` (see the module
97
+ * comment), so plain bare-specifier resolution reaches every `@meith/*`
98
+ * package this app's dependency graph needs, and `transpilePackages`
99
+ * (apps/community/next.config.mjs) is what lets Next compile the `.ts`
100
+ * source that resolution lands on. A board built *inside* this monorepo's
101
+ * own pnpm install has no such hoisting — packages here resolve each other
102
+ * through tsconfig path aliases straight to source (docs/architecture.md,
103
+ * "The board-config seam"; docs/development.md, "The workspace") rather than
104
+ * through real `dependencies` entries, so plain node_modules resolution
105
+ * finds nothing for most of them.
106
+ *
107
+ * `FORUM_ALIASES_FROM`, set only by docker/Dockerfile for `boards/stock`,
108
+ * names that other tsconfig (this repository's own `tsconfig.base.json`).
109
+ * When set, every `@meith/*` alias it declares is copied into the
110
+ * materialized app's own generated tsconfig, rebased to be relative to
111
+ * `.meith/app` — the same aliases apps/community's own tsconfig.json
112
+ * hand-maintains for exactly this reason. Unset (the default, and the only
113
+ * path a real external board ever takes), this is a no-op.
114
+ */
115
+ function monorepoAliases() {
116
+ const configFile = process.env.FORUM_ALIASES_FROM
117
+ if (!configFile) return {}
118
+
119
+ const sourceDir = dirname(resolve(configFile))
120
+ const source = JSON.parse(readFileSync(configFile, 'utf8'))
121
+ const paths = source.compilerOptions?.paths ?? {}
122
+
123
+ const aliases = {}
124
+ for (const [alias, targets] of Object.entries(paths)) {
125
+ // `@board/config`/`@board/plugins` are this workspace's own seam, wired
126
+ // below to *this* board's files — never to whatever apps/community's own
127
+ // tsconfig happens to alias them to.
128
+ if (alias === '@board/config' || alias === '@board/plugins') continue
129
+ aliases[alias] = targets.map((target) => toPosixRelative(appDir, join(sourceDir, target)))
130
+ }
131
+ return aliases
132
+ }
133
+
134
+ function materialize() {
135
+ const boardConfig = join(workspaceRoot, 'community.config.ts')
136
+ const boardPlugins = join(workspaceRoot, 'community.plugins.ts')
137
+
138
+ if (!existsSync(boardConfig)) {
139
+ fail(
140
+ `no community.config.ts in ${workspaceRoot}. Run forum-web from a board's own ` +
141
+ 'directory — the one create-meith scaffolded, or one shaped like it.',
142
+ )
143
+ }
144
+
145
+ // Replace each shipped entry, but never `rm -rf` the whole directory:
146
+ // `.next` lives here too once a build has run, and `forum-web start` needs
147
+ // that build still on disk after this same function re-materializes the
148
+ // sources ahead of launching the standalone server.
149
+ mkdirSync(appDir, { recursive: true })
150
+
151
+ for (const entry of APP_ENTRIES) {
152
+ const source = join(packageRoot, entry)
153
+ const target = join(appDir, entry)
154
+ rmSync(target, { recursive: true, force: true })
155
+ if (!existsSync(source)) continue
156
+ cpSync(source, target, { recursive: true })
157
+ }
158
+
159
+ const tsconfig = {
160
+ compilerOptions: {
161
+ target: 'ES2022',
162
+ lib: ['dom', 'dom.iterable', 'esnext'],
163
+ module: 'esnext',
164
+ moduleResolution: 'bundler',
165
+ jsx: 'preserve',
166
+ allowJs: false,
167
+ resolveJsonModule: true,
168
+ esModuleInterop: true,
169
+ isolatedModules: true,
170
+ skipLibCheck: true,
171
+ noEmit: true,
172
+ incremental: true,
173
+ strict: true,
174
+ plugins: [{ name: 'next' }],
175
+ paths: {
176
+ ...monorepoAliases(),
177
+ '@/*': ['./src/*'],
178
+ '@board/config': [toPosixRelative(appDir, boardConfig)],
179
+ '@board/plugins': [toPosixRelative(appDir, boardPlugins)],
180
+ },
181
+ },
182
+ include: ['next-env.d.ts', '**/*.ts', '**/*.tsx', '.next/types/**/*.ts'],
183
+ exclude: ['node_modules'],
184
+ }
185
+
186
+ writeFileSync(join(appDir, 'tsconfig.json'), `${JSON.stringify(tsconfig, null, 2)}\n`)
187
+
188
+ // next dev/build reads its own next-env.d.ts if present; an empty one is
189
+ // enough, and next regenerates it with the right content on first run.
190
+ writeFileSync(
191
+ join(appDir, 'next-env.d.ts'),
192
+ '/// <reference types="next" />\n/// <reference types="next/image-types/global" />\n',
193
+ )
194
+ }
195
+
196
+ function resolveNextBin() {
197
+ // Resolved from this package's own directory rather than the workspace
198
+ // root: `next` is @meith/web's dependency, not necessarily the workspace
199
+ // manifest's, and resolving from here finds it either way — hoisted to
200
+ // the workspace root (npm, yarn classic) or nested under this package's
201
+ // own node_modules (pnpm's default, non-hoisted layout).
202
+ const require = createRequire(join(packageRoot, 'package.json'))
203
+ try {
204
+ return require.resolve('next/dist/bin/next')
205
+ } catch {
206
+ fail("could not find next's own CLI from @meith/web — is next installed in this workspace?")
207
+ }
208
+ }
209
+
210
+ function run(executable, args, cwd) {
211
+ const child = spawn(executable, args, { cwd, stdio: 'inherit' })
212
+ child.on('exit', (code, signal) => process.exit(code ?? (signal ? 1 : 0)))
213
+ child.on('error', (error) => fail(error.message))
214
+ }
215
+
216
+ const [, , command, ...rest] = process.argv
217
+
218
+ if (!['dev', 'build', 'start'].includes(command ?? '')) {
219
+ console.error('Usage: forum-web <dev|build|start> [next arguments]')
220
+ process.exit(1)
221
+ }
222
+
223
+ materialize()
224
+
225
+ if (command === 'start') {
226
+ // `next.config.mjs` sets `output: 'standalone'`, and a standalone build is
227
+ // run from its own traced server.js, not `next start` (see docker/Dockerfile
228
+ // and docker/entrypoint.sh, which run the image's board the same way). The
229
+ // tracing root is the workspace root (see the module comment on why
230
+ // `.meith/app` sits exactly two levels below it), so the standalone bundle
231
+ // preserves that same relative path down to the app directory.
232
+ const standaloneRoot = join(appDir, '.next', 'standalone')
233
+ const serverScript = join(standaloneRoot, relative(workspaceRoot, appDir), 'server.js')
234
+ if (!existsSync(serverScript)) {
235
+ fail(`no standalone build at ${serverScript} — run "forum-web build" first.`)
236
+ }
237
+ run(process.execPath, [serverScript, ...rest], standaloneRoot)
238
+ } else {
239
+ const nextBin = resolveNextBin()
240
+ run(process.execPath, [nextBin, command, ...rest], appDir)
241
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "base-nova",
4
+ "rsc": true,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "app/globals.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "aliases": {
14
+ "components": "@/components",
15
+ "utils": "@/lib/utils",
16
+ "ui": "@/components/ui",
17
+ "lib": "@/lib",
18
+ "hooks": "@/hooks"
19
+ },
20
+ "iconLibrary": "lucide"
21
+ }
@@ -0,0 +1,18 @@
1
+ export async function register(): Promise<void> {
2
+ // biome-ignore lint/style/noProcessEnv: build-time runtime token, not config; see above
3
+ if (process.env.NEXT_RUNTIME !== 'nodejs') return
4
+
5
+ const { assertRuntimeEnv, initTracing } = await import('@meith/core')
6
+
7
+ const env = assertRuntimeEnv()
8
+
9
+ if (env.DATA_SOURCE === 'fixture') {
10
+ // biome-ignore lint/suspicious/noConsole: pre-logger boot diagnostic
11
+ console.info(
12
+ '[forum] DATA_SOURCE=fixture — running against in-memory sample data. ' +
13
+ 'Set DATABASE_URL to use Postgres.',
14
+ )
15
+ }
16
+
17
+ await initTracing('meith-web')
18
+ }
@@ -0,0 +1,182 @@
1
+ import { existsSync } from 'node:fs'
2
+ import path from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
4
+
5
+ const here = path.dirname(fileURLToPath(import.meta.url))
6
+
7
+ // Two directories up from this file's own location — correct whenever this
8
+ // file sits at that fixed depth below the real workspace root: in place at
9
+ // `apps/community` inside this monorepo, or materialized to `.meith/app`
10
+ // inside a *board whose own directory sits two levels below its own
11
+ // `node_modules`* (a create-meith scaffold with hoisted node_modules, per
12
+ // docs/development.md, "Consuming the board from a workspace").
13
+ //
14
+ // `boards/stock` (docker/Dockerfile) is neither: it is a workspace member of
15
+ // *this* monorepo's own pnpm install, which does not hoist, so its real
16
+ // dependencies (including `next` itself) resolve through this repository's
17
+ // root `node_modules`, two directories further up again — a fixed offset
18
+ // this file cannot compute from its own path alone, because pnpm resolves
19
+ // its dependencies through symlinks into a central store rather than by
20
+ // nesting a workspace member two directories below everything it needs.
21
+ // FORUM_WORKSPACE_ROOT lets the Dockerfile say so explicitly, without
22
+ // changing the default for every other consumer this computation already
23
+ // serves correctly.
24
+ const workspaceRoot = process.env.FORUM_WORKSPACE_ROOT
25
+ ? path.resolve(process.env.FORUM_WORKSPACE_ROOT)
26
+ : path.join(here, '../../')
27
+
28
+ // How many `../` this file's own directory is below workspaceRoot — 2 by
29
+ // construction in the default case (see above), more when
30
+ // FORUM_WORKSPACE_ROOT points further up. Used below instead of a literal
31
+ // `'../../'` wherever a *relative* climb has to reach the same root, because
32
+ // `outputFileTracingIncludes` (unlike `outputFileTracingRoot` and
33
+ // `turbopack.root`) resolves its globs relative to this directory itself,
34
+ // not against `workspaceRoot` — an absolute glob there silently matches
35
+ // nothing useful once it is rejoined onto this directory downstream.
36
+ const upToWorkspaceRoot = path.relative(here, workspaceRoot).split(path.sep).join('/')
37
+
38
+ const loadedEnvFiles = []
39
+ for (const name of ['.env.local', '.env']) {
40
+ const file = path.join(workspaceRoot, name)
41
+ if (!existsSync(file)) continue
42
+ process.loadEnvFile(file)
43
+ loadedEnvFiles.push(name)
44
+ }
45
+
46
+ if (process.env.NODE_ENV !== 'production' && loadedEnvFiles.length > 0) {
47
+ console.log(`- Environments: ${loadedEnvFiles.join(', ')} (${workspaceRoot})`)
48
+ }
49
+
50
+ const nextConfig = {
51
+ output: 'standalone',
52
+ poweredByHeader: false,
53
+ distDir: process.env.FORUM_DIST_DIR ?? '.next',
54
+
55
+ serverExternalPackages: [
56
+ '@aws-sdk/client-s3',
57
+ '@aws-sdk/s3-request-presigner',
58
+ 'postgres',
59
+ '@jsquash/jpeg',
60
+ '@jsquash/png',
61
+ '@jsquash/resize',
62
+ 'nodemailer',
63
+ ],
64
+ outputFileTracingRoot: workspaceRoot,
65
+ // Turbopack infers a project root by walking up for a lockfile, and
66
+ // otherwise stops at this app's own directory — which for a materialized
67
+ // app (apps/community/bin/forum-web.mjs) is two directories below the
68
+ // real one. Left unset, Turbopack's own Node.js transform pool (postcss,
69
+ // for instance) cannot see the invoking workspace's node_modules at all,
70
+ // and fails with "Cannot find module" for a dependency that plain Node
71
+ // resolution finds without trouble.
72
+ turbopack: {
73
+ root: workspaceRoot,
74
+ },
75
+ // The output-file tracer only follows the CJS half of @swc/helpers' dual
76
+ // package and misses the `esm/` variant next's own require-hook resolves at
77
+ // runtime, so the standalone build ships a `@swc/helpers` directory missing
78
+ // its esm/ half. next resolves the package from its own nested pnpm store
79
+ // entry (node_modules/.pnpm/next@…/node_modules/@swc/helpers), which is a
80
+ // symlink into node_modules/.pnpm/@swc+helpers@0.5.23/node_modules/@swc/helpers
81
+ // — so that is the path that has to be complete, not the app's own copy.
82
+ outputFileTracingIncludes: {
83
+ '/**': [
84
+ `${upToWorkspaceRoot}/node_modules/.pnpm/@swc+helpers@0.5.23/node_modules/@swc/helpers/**/*`,
85
+ ],
86
+ },
87
+ images: {
88
+ unoptimized: true,
89
+ },
90
+ // Every `@meith/*` package this app's dependency graph reaches — not just
91
+ // the ones apps/community imports directly. All of them ship TypeScript
92
+ // source with no build step (see docs/release.md, "They ship TypeScript
93
+ // source, deliberately"), and inside this monorepo every one of them is
94
+ // resolved through a tsconfig path alias straight to its source file,
95
+ // bypassing node_modules — which is why this list used to be a small,
96
+ // seemingly arbitrary subset: only the packages some other resolution path
97
+ // happened to touch via node_modules ever needed it here.
98
+ //
99
+ // A materialized workspace's own generated tsconfig carries no such alias
100
+ // map (see apps/community/bin/forum-web.mjs) — only `@board/config` and
101
+ // `@board/plugins`, the seam itself. Every other `@meith/*` specifier
102
+ // resolves the ordinary way once this package is npm-installed, which
103
+ // means every one of them needs this same source-compilation treatment,
104
+ // or the build fails with "Unknown module type" on its `src/index.ts`.
105
+ // Computed by walking this app's own imports plus every `@meith/*`
106
+ // package's own "dependencies" transitively — see docs/development.md,
107
+ // "Consuming the board from a workspace".
108
+ transpilePackages: [
109
+ '@meith/accounts',
110
+ '@meith/admin',
111
+ '@meith/antispam',
112
+ '@meith/api',
113
+ '@meith/attachments',
114
+ '@meith/authorization',
115
+ '@meith/avatars',
116
+ '@meith/core',
117
+ '@meith/db',
118
+ '@meith/demo',
119
+ '@meith/drafts',
120
+ '@meith/drivers',
121
+ '@meith/events',
122
+ '@meith/forums',
123
+ '@meith/groups',
124
+ '@meith/i18n',
125
+ '@meith/import',
126
+ '@meith/install',
127
+ '@meith/mail',
128
+ '@meith/markdown',
129
+ '@meith/marketplace',
130
+ '@meith/messages',
131
+ '@meith/moderation',
132
+ '@meith/notifications',
133
+ '@meith/plugin-dues',
134
+ '@meith/plugin-kit',
135
+ '@meith/polls',
136
+ '@meith/posts',
137
+ '@meith/profile-fields',
138
+ '@meith/relations',
139
+ '@meith/reputation',
140
+ '@meith/runtime',
141
+ '@meith/search',
142
+ '@meith/settings',
143
+ '@meith/signatures',
144
+ '@meith/subscriptions',
145
+ '@meith/tasks',
146
+ '@meith/theme-clubhouse',
147
+ '@meith/theme-default',
148
+ '@meith/theme-kit',
149
+ '@meith/theme-midnight',
150
+ '@meith/theme-phasebook',
151
+ '@meith/theme-raidframe',
152
+ '@meith/threads',
153
+ '@meith/ui',
154
+ '@meith/upgrade',
155
+ // Only reached through the `@meith/web/config` subpath, and only from a
156
+ // materialized workspace's own community.config.ts — inside this
157
+ // monorepo apps/community never imports itself by package name. Real
158
+ // once npm resolves this package into another workspace's node_modules,
159
+ // so it needs the same source-compilation treatment as everything else
160
+ // in this list.
161
+ '@meith/web',
162
+ ],
163
+ async headers() {
164
+ return [
165
+ {
166
+ source: '/:path*',
167
+ headers: [
168
+ { key: 'X-Content-Type-Options', value: 'nosniff' },
169
+ { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
170
+ { key: 'Strict-Transport-Security', value: 'max-age=63072000' },
171
+ { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
172
+ {
173
+ key: 'Permissions-Policy',
174
+ value: 'camera=(), microphone=(), geolocation=()',
175
+ },
176
+ ],
177
+ },
178
+ ]
179
+ },
180
+ }
181
+
182
+ export default nextConfig
package/package.json ADDED
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "@meith/web",
3
+ "version": "0.16.0",
4
+ "description": "The board itself: the Next.js app, and the forum-web bin that materializes it into an external board workspace.",
5
+ "license": "LGPL-3.0-or-later",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/meith-dev/meith.git",
9
+ "directory": "apps/community"
10
+ },
11
+ "bin": {
12
+ "forum-web": "./bin/forum-web.mjs"
13
+ },
14
+ "exports": {
15
+ "./config": "./src/config.ts"
16
+ },
17
+ "files": [
18
+ "bin",
19
+ "app",
20
+ "src",
21
+ "next.config.mjs",
22
+ "postcss.config.mjs",
23
+ "components.json",
24
+ "instrumentation.ts",
25
+ "proxy.ts",
26
+ "!src/**/*.test.*",
27
+ "!src/**/*.type-test.*",
28
+ "!app/**/*.test.*",
29
+ "!app/**/*.type-test.*"
30
+ ],
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "dependencies": {
35
+ "@swc/helpers": "0.5.23",
36
+ "@tailwindcss/postcss": "^4.3.3",
37
+ "next": "16.3.1",
38
+ "postcss": "^8.5",
39
+ "react": "19.2.8",
40
+ "react-dom": "19.2.8",
41
+ "tailwindcss": "^4.3.3",
42
+ "typescript": "7.0.2",
43
+ "@types/react": "^19",
44
+ "@types/react-dom": "^19",
45
+ "@meith/accounts": "0.16.0",
46
+ "@meith/antispam": "0.16.0",
47
+ "@meith/authorization": "0.16.0",
48
+ "@meith/attachments": "0.16.0",
49
+ "@meith/api": "0.16.0",
50
+ "@meith/admin": "0.16.0",
51
+ "@meith/avatars": "0.16.0",
52
+ "@meith/db": "0.16.0",
53
+ "@meith/drivers": "0.16.0",
54
+ "@meith/events": "0.16.0",
55
+ "@meith/drafts": "0.16.0",
56
+ "@meith/forums": "0.16.0",
57
+ "@meith/groups": "0.16.0",
58
+ "@meith/core": "0.16.0",
59
+ "@meith/demo": "0.16.0",
60
+ "@meith/mail": "0.16.0",
61
+ "@meith/install": "0.16.0",
62
+ "@meith/import": "0.16.0",
63
+ "@meith/markdown": "0.16.0",
64
+ "@meith/marketplace": "0.16.0",
65
+ "@meith/moderation": "0.16.0",
66
+ "@meith/notifications": "0.16.0",
67
+ "@meith/profile-fields": "0.16.0",
68
+ "@meith/plugin-kit": "0.16.0",
69
+ "@meith/posts": "0.16.0",
70
+ "@meith/polls": "0.16.0",
71
+ "@meith/i18n": "0.16.0",
72
+ "@meith/reputation": "0.16.0",
73
+ "@meith/search": "0.16.0",
74
+ "@meith/signatures": "0.16.0",
75
+ "@meith/settings": "0.16.0",
76
+ "@meith/subscriptions": "0.16.0",
77
+ "@meith/theme-clubhouse": "0.16.0",
78
+ "@meith/relations": "0.16.0",
79
+ "@meith/messages": "0.16.0",
80
+ "@meith/runtime": "0.16.0",
81
+ "@meith/plugin-dues": "0.16.0",
82
+ "@meith/theme-kit": "0.16.0",
83
+ "@meith/tasks": "0.16.0",
84
+ "@meith/theme-midnight": "0.16.0",
85
+ "@meith/theme-default": "0.16.0",
86
+ "@meith/theme-phasebook": "0.16.0",
87
+ "@meith/theme-raidframe": "0.16.0",
88
+ "@meith/threads": "0.16.0",
89
+ "@meith/upgrade": "0.16.0",
90
+ "@meith/ui": "0.16.0"
91
+ },
92
+ "scripts": {
93
+ "dev": "next dev",
94
+ "build": "next build",
95
+ "start": "next start",
96
+ "lint": "biome check .",
97
+ "typecheck": "tsc -p tsconfig.json --noEmit"
98
+ }
99
+ }
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ '@tailwindcss/postcss': {},
4
+ },
5
+ }
6
+
7
+ export default config