@nextsparkjs/core 0.1.0-beta.189 → 0.1.0-beta.190

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 (456) hide show
  1. package/dist/components/api/keys/CreateApiKeyDialog.d.ts.map +1 -1
  2. package/dist/components/api/keys/CreateApiKeyDialog.js +2 -1
  3. package/dist/components/app/layouts/PublicFooter.d.ts.map +1 -1
  4. package/dist/components/app/layouts/PublicFooter.js +2 -23
  5. package/dist/components/app/misc/ThemeToggle.d.ts.map +1 -1
  6. package/dist/components/app/misc/ThemeToggle.js +2 -1
  7. package/dist/components/auth/forms/LoginForm.js +1 -1
  8. package/dist/components/auth/forms/SignupForm.d.ts.map +1 -1
  9. package/dist/components/auth/forms/SignupForm.js +2 -1
  10. package/dist/components/auth/pages/AuthErrorPage.d.ts.map +1 -1
  11. package/dist/components/auth/pages/AuthErrorPage.js +2 -1
  12. package/dist/components/billing/ManageBillingButton.d.ts.map +1 -1
  13. package/dist/components/billing/ManageBillingButton.js +2 -1
  14. package/dist/components/dashboard/block-editor/array-field.d.ts.map +1 -1
  15. package/dist/components/dashboard/block-editor/array-field.js +2 -1
  16. package/dist/components/dashboard/block-editor/block-picker.d.ts.map +1 -1
  17. package/dist/components/dashboard/block-editor/block-picker.js +2 -1
  18. package/dist/components/dashboard/block-editor/builder-editor-view.d.ts.map +1 -1
  19. package/dist/components/dashboard/block-editor/builder-editor-view.js +3 -2
  20. package/dist/components/dashboard/block-editor/config-panel.d.ts.map +1 -1
  21. package/dist/components/dashboard/block-editor/config-panel.js +3 -2
  22. package/dist/components/dashboard/block-editor/dynamic-form.d.ts.map +1 -1
  23. package/dist/components/dashboard/block-editor/dynamic-form.js +2 -1
  24. package/dist/components/dashboard/block-editor/entity-fields-sidebar.d.ts.map +1 -1
  25. package/dist/components/dashboard/block-editor/entity-fields-sidebar.js +3 -2
  26. package/dist/components/dashboard/block-editor/pattern-reference-preview.d.ts.map +1 -1
  27. package/dist/components/dashboard/block-editor/pattern-reference-preview.js +2 -1
  28. package/dist/components/dashboard/layouts/TopNavbar.d.ts.map +1 -1
  29. package/dist/components/dashboard/layouts/TopNavbar.js +4 -3
  30. package/dist/components/dashboard/misc/SearchDropdown.d.ts.map +1 -1
  31. package/dist/components/dashboard/misc/SearchDropdown.js +2 -1
  32. package/dist/components/dashboard/mobile/MobileTopBar.d.ts.map +1 -1
  33. package/dist/components/dashboard/mobile/MobileTopBar.js +2 -1
  34. package/dist/components/devtools/BlockDetailViewer.d.ts.map +1 -1
  35. package/dist/components/devtools/BlockDetailViewer.js +2 -1
  36. package/dist/components/devtools/BlocksViewer.d.ts.map +1 -1
  37. package/dist/components/devtools/BlocksViewer.js +2 -1
  38. package/dist/components/devtools/ConfigViewer.d.ts.map +1 -1
  39. package/dist/components/devtools/ConfigViewer.js +3 -2
  40. package/dist/components/devtools/TestCasesViewer.d.ts.map +1 -1
  41. package/dist/components/devtools/TestCasesViewer.js +3 -2
  42. package/dist/components/devtools/TestCoverageDashboard.d.ts.map +1 -1
  43. package/dist/components/devtools/TestCoverageDashboard.js +2 -1
  44. package/dist/components/devtools/api-explorer/ApiDocsModal.d.ts.map +1 -1
  45. package/dist/components/devtools/api-explorer/ApiDocsModal.js +0 -0
  46. package/dist/components/devtools/api-explorer/ApiExplorer.d.ts.map +1 -1
  47. package/dist/components/devtools/api-explorer/ApiExplorer.js +2 -1
  48. package/dist/components/devtools/scheduled-actions/actions-table.d.ts.map +1 -1
  49. package/dist/components/devtools/scheduled-actions/actions-table.js +3 -2
  50. package/dist/components/docs/docs-sidebar.d.ts.map +1 -1
  51. package/dist/components/docs/docs-sidebar.js +3 -2
  52. package/dist/components/entities/EntityFieldRenderer.d.ts.map +1 -1
  53. package/dist/components/entities/EntityFieldRenderer.js +2 -1
  54. package/dist/components/entities/EntityList.d.ts.map +1 -1
  55. package/dist/components/entities/EntityList.js +2 -1
  56. package/dist/components/entities/EntityTable.d.ts.map +1 -1
  57. package/dist/components/entities/EntityTable.js +3 -2
  58. package/dist/components/entities/ErrorBoundary.d.ts.map +1 -1
  59. package/dist/components/entities/ErrorBoundary.js +2 -1
  60. package/dist/components/entities/wrappers/EntityDetailWrapper.d.ts.map +1 -1
  61. package/dist/components/entities/wrappers/EntityDetailWrapper.js +3 -2
  62. package/dist/components/media/MediaCard.d.ts.map +1 -1
  63. package/dist/components/media/MediaCard.js +2 -1
  64. package/dist/components/media/MediaDetailPanel.d.ts.map +1 -1
  65. package/dist/components/media/MediaDetailPanel.js +2 -1
  66. package/dist/components/media/MediaList.d.ts.map +1 -1
  67. package/dist/components/media/MediaList.js +2 -1
  68. package/dist/components/media/MediaSelector.d.ts.map +1 -1
  69. package/dist/components/media/MediaSelector.js +2 -1
  70. package/dist/components/media/MediaUploadZone.d.ts.map +1 -1
  71. package/dist/components/media/MediaUploadZone.js +2 -1
  72. package/dist/components/public/entities/PublicEntityDetail.d.ts.map +1 -1
  73. package/dist/components/public/entities/PublicEntityDetail.js +2 -1
  74. package/dist/components/teams/TeamPendingInvitations.d.ts.map +1 -1
  75. package/dist/components/teams/TeamPendingInvitations.js +3 -2
  76. package/dist/components/ui/accordion.js +1 -1
  77. package/dist/components/ui/audio-upload.d.ts.map +1 -1
  78. package/dist/components/ui/audio-upload.js +2 -1
  79. package/dist/components/ui/avatar.d.ts +17 -1
  80. package/dist/components/ui/avatar.d.ts.map +1 -1
  81. package/dist/components/ui/avatar.js +29 -2
  82. package/dist/components/ui/badge.js +1 -1
  83. package/dist/components/ui/breadcrumb.d.ts +13 -0
  84. package/dist/components/ui/breadcrumb.d.ts.map +1 -1
  85. package/dist/components/ui/breadcrumb.js +23 -10
  86. package/dist/components/ui/button.js +1 -1
  87. package/dist/components/ui/card.js +1 -1
  88. package/dist/components/ui/checkbox.js +1 -1
  89. package/dist/components/ui/file-upload.d.ts.map +1 -1
  90. package/dist/components/ui/file-upload.js +2 -1
  91. package/dist/components/ui/image-upload.d.ts.map +1 -1
  92. package/dist/components/ui/image-upload.js +4 -3
  93. package/dist/components/ui/input.js +1 -1
  94. package/dist/components/ui/label.js +1 -1
  95. package/dist/components/ui/optimized-image.d.ts.map +1 -1
  96. package/dist/components/ui/optimized-image.js +5 -0
  97. package/dist/components/ui/pagination.d.ts +1 -1
  98. package/dist/components/ui/pagination.d.ts.map +1 -1
  99. package/dist/components/ui/pagination.js +3 -0
  100. package/dist/components/ui/progress.js +1 -1
  101. package/dist/components/ui/relation-display.d.ts.map +1 -1
  102. package/dist/components/ui/relation-display.js +3 -2
  103. package/dist/components/ui/separator.js +1 -1
  104. package/dist/components/ui/simple-relation-select.d.ts.map +1 -1
  105. package/dist/components/ui/simple-relation-select.js +7 -6
  106. package/dist/components/ui/skeleton.js +1 -1
  107. package/dist/components/ui/slider.js +1 -1
  108. package/dist/components/ui/switch.js +1 -1
  109. package/dist/components/ui/tabs.js +1 -1
  110. package/dist/components/ui/textarea.js +1 -1
  111. package/dist/components/ui/user-display.d.ts.map +1 -1
  112. package/dist/components/ui/user-display.js +2 -1
  113. package/dist/components/ui/user-select.d.ts.map +1 -1
  114. package/dist/components/ui/user-select.js +2 -1
  115. package/dist/components/ui/video-upload.d.ts.map +1 -1
  116. package/dist/components/ui/video-upload.js +3 -2
  117. package/dist/components/users/tables/UsersTable.d.ts.map +1 -1
  118. package/dist/components/users/tables/UsersTable.js +3 -2
  119. package/dist/contexts/SubscriptionContext.d.ts.map +1 -1
  120. package/dist/contexts/SubscriptionContext.js +4 -3
  121. package/dist/contexts/TeamContext.d.ts.map +1 -1
  122. package/dist/contexts/TeamContext.js +3 -2
  123. package/dist/hooks/useAccountPreferencesSync.d.ts.map +1 -1
  124. package/dist/hooks/useAccountPreferencesSync.js +2 -1
  125. package/dist/hooks/useApiExplorerNavigation.d.ts.map +1 -1
  126. package/dist/hooks/useApiExplorerNavigation.js +2 -1
  127. package/dist/hooks/useAuth.d.ts.map +1 -1
  128. package/dist/hooks/useAuth.js +3 -2
  129. package/dist/hooks/useEnsureUserMetadata.d.ts.map +1 -1
  130. package/dist/hooks/useEnsureUserMetadata.js +3 -2
  131. package/dist/hooks/useEntityWithMeta.d.ts.map +1 -1
  132. package/dist/hooks/useEntityWithMeta.js +3 -2
  133. package/dist/hooks/useInvoice.d.ts.map +1 -1
  134. package/dist/hooks/useInvoice.js +2 -1
  135. package/dist/hooks/useInvoices.d.ts.map +1 -1
  136. package/dist/hooks/useInvoices.js +2 -1
  137. package/dist/hooks/useMedia.d.ts.map +1 -1
  138. package/dist/hooks/useMedia.js +10 -9
  139. package/dist/hooks/useMediaUpload.d.ts.map +1 -1
  140. package/dist/hooks/useMediaUpload.js +2 -1
  141. package/dist/hooks/useMembership.d.ts.map +1 -1
  142. package/dist/hooks/useMembership.js +3 -2
  143. package/dist/hooks/usePatternUsages.d.ts.map +1 -1
  144. package/dist/hooks/usePatternUsages.js +3 -2
  145. package/dist/hooks/usePrefetch.d.ts.map +1 -1
  146. package/dist/hooks/usePrefetch.js +3 -2
  147. package/dist/hooks/useQuota.d.ts.map +1 -1
  148. package/dist/hooks/useQuota.js +2 -1
  149. package/dist/hooks/useTeamInvitations.d.ts.map +1 -1
  150. package/dist/hooks/useTeamInvitations.js +4 -3
  151. package/dist/hooks/useTeamMembers.d.ts.map +1 -1
  152. package/dist/hooks/useTeamMembers.js +5 -4
  153. package/dist/hooks/useTeamUpdate.d.ts.map +1 -1
  154. package/dist/hooks/useTeamUpdate.js +2 -1
  155. package/dist/hooks/useUserProfile.d.ts.map +1 -1
  156. package/dist/hooks/useUserProfile.js +3 -2
  157. package/dist/hooks/useUserSettings.d.ts.map +1 -1
  158. package/dist/hooks/useUserSettings.js +3 -2
  159. package/dist/lib/actions/entity.actions.d.ts.map +1 -1
  160. package/dist/lib/actions/entity.actions.js +2 -1
  161. package/dist/lib/api/entities.d.ts.map +1 -1
  162. package/dist/lib/api/entities.js +4 -3
  163. package/dist/lib/auth/verify-email-link.d.ts +10 -0
  164. package/dist/lib/auth/verify-email-link.d.ts.map +1 -0
  165. package/dist/lib/auth/verify-email-link.js +14 -0
  166. package/dist/lib/auth-client.d.ts +2 -0
  167. package/dist/lib/auth-client.d.ts.map +1 -1
  168. package/dist/lib/auth-client.js +4 -0
  169. package/dist/lib/auth.d.ts.map +1 -1
  170. package/dist/lib/auth.js +10 -2
  171. package/dist/lib/base-path.d.ts +85 -0
  172. package/dist/lib/base-path.d.ts.map +1 -0
  173. package/dist/lib/base-path.js +79 -0
  174. package/dist/lib/billing/schema.d.ts +1 -1
  175. package/dist/lib/billing/schema.d.ts.map +1 -1
  176. package/dist/lib/billing/schema.js +1 -1
  177. package/dist/lib/blocks/sanitize-html.d.ts.map +1 -1
  178. package/dist/lib/blocks/sanitize-html.js +18 -2
  179. package/dist/lib/cache/revalidate-tag.d.ts +14 -0
  180. package/dist/lib/cache/revalidate-tag.d.ts.map +1 -0
  181. package/dist/lib/cache/revalidate-tag.js +8 -0
  182. package/dist/lib/config/dashboard-schema.d.ts +1 -1
  183. package/dist/lib/config/dashboard-schema.d.ts.map +1 -1
  184. package/dist/lib/config/dashboard-schema.js +1 -1
  185. package/dist/lib/config/types.d.ts +36 -16
  186. package/dist/lib/config/types.d.ts.map +1 -1
  187. package/dist/lib/docs/access.d.ts +28 -0
  188. package/dist/lib/docs/access.d.ts.map +1 -0
  189. package/dist/lib/docs/access.js +16 -0
  190. package/dist/lib/docs/parser.d.ts.map +1 -1
  191. package/dist/lib/docs/parser.js +2 -1
  192. package/dist/lib/docs/remark-doc-links.d.ts +14 -0
  193. package/dist/lib/docs/remark-doc-links.d.ts.map +1 -0
  194. package/dist/lib/docs/remark-doc-links.js +38 -0
  195. package/dist/lib/entities/api-generator.d.ts +1 -1
  196. package/dist/lib/entities/api-generator.d.ts.map +1 -1
  197. package/dist/lib/entities/api-generator.js +1 -1
  198. package/dist/lib/entities/schema-generator.d.ts +1 -1
  199. package/dist/lib/entities/schema-generator.d.ts.map +1 -1
  200. package/dist/lib/entities/schema-generator.js +1 -1
  201. package/dist/lib/mcp/engine.js +1 -1
  202. package/dist/lib/mcp/schema-builder.d.ts +1 -1
  203. package/dist/lib/mcp/schema-builder.d.ts.map +1 -1
  204. package/dist/lib/mcp/schema-builder.js +1 -1
  205. package/dist/lib/mcp/tool-generator.js +1 -1
  206. package/dist/lib/mcp/types.d.ts +1 -1
  207. package/dist/lib/mcp/types.d.ts.map +1 -1
  208. package/dist/lib/media/schemas.d.ts +1 -1
  209. package/dist/lib/media/schemas.d.ts.map +1 -1
  210. package/dist/lib/media/schemas.js +1 -1
  211. package/dist/lib/middleware/index.d.ts +5 -1
  212. package/dist/lib/middleware/index.d.ts.map +1 -1
  213. package/dist/lib/middleware/index.js +3 -2
  214. package/dist/lib/services/meta.service.d.ts +60 -0
  215. package/dist/lib/services/meta.service.d.ts.map +1 -1
  216. package/dist/lib/services/meta.service.js +132 -12
  217. package/dist/lib/services/middleware.service.d.ts.map +1 -1
  218. package/dist/lib/services/middleware.service.js +3 -2
  219. package/dist/lib/teams/schema.d.ts +1 -1
  220. package/dist/lib/teams/schema.d.ts.map +1 -1
  221. package/dist/lib/teams/schema.js +1 -1
  222. package/dist/lib/teams/teams.api.d.ts.map +1 -1
  223. package/dist/lib/teams/teams.api.js +4 -3
  224. package/dist/lib/user-data-client.d.ts.map +1 -1
  225. package/dist/lib/user-data-client.js +3 -2
  226. package/dist/lib/validation/invoices.d.ts +1 -1
  227. package/dist/lib/validation/invoices.d.ts.map +1 -1
  228. package/dist/lib/validation/invoices.js +1 -1
  229. package/dist/lib/validation-schemas.d.ts +1 -1
  230. package/dist/lib/validation-schemas.d.ts.map +1 -1
  231. package/dist/lib/validation-schemas.js +1 -1
  232. package/dist/lib/validation.d.ts +1 -1
  233. package/dist/lib/validation.d.ts.map +1 -1
  234. package/dist/lib/validation.js +1 -1
  235. package/dist/messages/de/footer.json +0 -1
  236. package/dist/messages/de/index.d.ts +0 -1
  237. package/dist/messages/de/index.d.ts.map +1 -1
  238. package/dist/messages/en/footer.json +0 -1
  239. package/dist/messages/en/index.d.ts +0 -1
  240. package/dist/messages/en/index.d.ts.map +1 -1
  241. package/dist/messages/es/footer.json +0 -1
  242. package/dist/messages/es/index.d.ts +0 -1
  243. package/dist/messages/es/index.d.ts.map +1 -1
  244. package/dist/messages/fr/footer.json +0 -1
  245. package/dist/messages/fr/index.d.ts +0 -1
  246. package/dist/messages/fr/index.d.ts.map +1 -1
  247. package/dist/messages/it/footer.json +0 -1
  248. package/dist/messages/it/index.d.ts +0 -1
  249. package/dist/messages/it/index.d.ts.map +1 -1
  250. package/dist/messages/pt/footer.json +0 -1
  251. package/dist/messages/pt/index.d.ts +0 -1
  252. package/dist/messages/pt/index.d.ts.map +1 -1
  253. package/dist/templates/app/(auth)/accept-invite/[token]/page.tsx +4 -3
  254. package/dist/templates/app/(auth)/verify-email/page.tsx +4 -3
  255. package/dist/templates/app/(public)/docs/[section]/[page]/page.tsx +11 -0
  256. package/dist/templates/app/api/auth/[...all]/route.ts +15 -14
  257. package/dist/templates/app/api/internal/user-metadata/route.ts +6 -8
  258. package/dist/templates/app/api/user/plan-flags/route.ts +1 -1
  259. package/dist/templates/app/api/user/profile/route.ts +12 -17
  260. package/dist/templates/app/api/v1/api-keys/route.ts +1 -1
  261. package/dist/templates/app/api/v1/auth/signup-with-invite/route.ts +2 -1
  262. package/dist/templates/app/api/v1/billing/cancel/route.ts +1 -1
  263. package/dist/templates/app/api/v1/billing/change-plan/route.ts +1 -1
  264. package/dist/templates/app/api/v1/billing/check-action/route.ts +1 -1
  265. package/dist/templates/app/api/v1/billing/checkout/route.ts +1 -1
  266. package/dist/templates/app/api/v1/blocks/validate/route.ts +1 -1
  267. package/dist/templates/app/api/v1/media/[id]/tags/route.ts +1 -1
  268. package/dist/templates/app/api/v1/post-categories/[id]/route.ts +1 -1
  269. package/dist/templates/app/api/v1/post-categories/route.ts +1 -1
  270. package/dist/templates/app/api/v1/teams/[teamId]/members/route.ts +2 -1
  271. package/dist/templates/app/api/v1/teams/[teamId]/subscription/route.ts +3 -5
  272. package/dist/templates/app/api/v1/teams/docs.md +4 -9
  273. package/dist/templates/app/api/v1/teams/switch/route.ts +1 -1
  274. package/dist/templates/app/api/v1/users/[id]/meta/[key]/route.ts +1 -1
  275. package/dist/templates/app/api/v1/users/[id]/route.ts +1 -1
  276. package/dist/templates/app/api/v1/users/route.ts +1 -1
  277. package/dist/templates/app/dashboard/(main)/media/page.tsx +3 -1
  278. package/dist/templates/app/dashboard/settings/api-keys/page.tsx +5 -4
  279. package/dist/templates/app/dashboard/settings/profile/page.tsx +3 -2
  280. package/dist/templates/app/devtools/scheduled-actions/page.tsx +2 -1
  281. package/dist/templates/app/superadmin/docs/[section]/[page]/page.tsx +16 -0
  282. package/dist/templates/app/superadmin/subscriptions/page.tsx +3 -2
  283. package/dist/templates/app/superadmin/teams/[teamId]/page.tsx +5 -4
  284. package/dist/templates/app/superadmin/users/[userId]/page.tsx +2 -1
  285. package/dist/templates/app/superadmin/users/page.tsx +2 -1
  286. package/dist/templates/blocks/cta-section/component.tsx +3 -2
  287. package/dist/templates/blocks/cta-section/schema.ts +1 -1
  288. package/dist/templates/blocks/features-grid/component.tsx +2 -1
  289. package/dist/templates/blocks/features-grid/schema.ts +1 -1
  290. package/dist/templates/blocks/hero/component.tsx +3 -2
  291. package/dist/templates/blocks/hero/schema.ts +1 -1
  292. package/dist/templates/blocks/testimonials/component.tsx +2 -1
  293. package/dist/templates/blocks/testimonials/schema.ts +1 -1
  294. package/dist/templates/blocks/text-content/component.tsx +2 -1
  295. package/dist/templates/blocks/text-content/schema.ts +1 -1
  296. package/dist/templates/ci-workflows/README.md +1 -1
  297. package/dist/templates/ci-workflows/github/cypress-regression.yml +1 -1
  298. package/dist/templates/ci-workflows/github/cypress-smoke.yml +1 -1
  299. package/dist/templates/contents/plugins/starter/plugin/api/example/route.ts.template +1 -1
  300. package/dist/templates/contents/themes/starter/blocks/cta-section/component.tsx +3 -2
  301. package/dist/templates/contents/themes/starter/blocks/cta-section/schema.ts +1 -1
  302. package/dist/templates/contents/themes/starter/blocks/features-grid/component.tsx +2 -1
  303. package/dist/templates/contents/themes/starter/blocks/features-grid/schema.ts +1 -1
  304. package/dist/templates/contents/themes/starter/blocks/hero/component.tsx +3 -2
  305. package/dist/templates/contents/themes/starter/blocks/hero/schema.ts +1 -1
  306. package/dist/templates/contents/themes/starter/blocks/testimonials/component.tsx +3 -2
  307. package/dist/templates/contents/themes/starter/blocks/testimonials/schema.ts +1 -1
  308. package/dist/templates/contents/themes/starter/blocks/text-content/component.tsx +2 -1
  309. package/dist/templates/contents/themes/starter/blocks/text-content/schema.ts +1 -1
  310. package/dist/templates/contents/themes/starter/entities/posts/components/post-header.tsx +2 -1
  311. package/dist/templates/contents/themes/starter/lib/hooks/useAnalyticsData.ts +2 -1
  312. package/dist/templates/contents/themes/starter/lib/hooks/useTaskStats.ts +2 -1
  313. package/dist/templates/eslint.config.mjs +133 -9
  314. package/dist/templates/features/blog/blocks/post-content/component.tsx +2 -1
  315. package/dist/templates/features/blog/blocks/post-content/schema.ts +1 -1
  316. package/dist/templates/features/blog/entities/posts/components/post-header.tsx +2 -1
  317. package/dist/templates/features/pages/blocks/hero/component.tsx +3 -2
  318. package/dist/templates/features/pages/blocks/hero/schema.ts +1 -1
  319. package/dist/templates/next.config.mjs +50 -29
  320. package/dist/templates/proxy.ts +100 -21
  321. package/dist/templates/public/sw.js +2 -2
  322. package/dist/templates/scripts/cy-run-prod.cjs +5 -5
  323. package/dist/types/blocks.d.ts +1 -1
  324. package/dist/types/blocks.d.ts.map +1 -1
  325. package/dist/types/blocks.js +1 -1
  326. package/package.json +9 -5
  327. package/scripts/build/docs-registry.mjs +7 -7
  328. package/scripts/build/registry/__tests__/billing-registry.test.mjs +43 -0
  329. package/scripts/build/registry/__tests__/build-output.test.mjs +209 -0
  330. package/scripts/build/registry/__tests__/copy-race-child.mjs +14 -0
  331. package/scripts/build/registry/__tests__/direct-fs-writes.mjs +203 -0
  332. package/scripts/build/registry/__tests__/globals-css-tag.test.mjs +66 -0
  333. package/scripts/build/registry/__tests__/icons-discovery.test.mjs +530 -29
  334. package/scripts/build/registry/__tests__/page-generator.test.mjs +211 -37
  335. package/scripts/build/registry/__tests__/published-signatures.test.mjs +239 -0
  336. package/scripts/build/registry/__tests__/route-file-rule.test.mjs +170 -0
  337. package/scripts/build/registry/__tests__/safe-fs.test.mjs +333 -0
  338. package/scripts/build/registry/__tests__/template-analysis.test.mjs +142 -0
  339. package/scripts/build/registry/__tests__/template-registry.test.mjs +279 -9
  340. package/scripts/build/registry/__tests__/templates-plan.test.mjs +128 -0
  341. package/scripts/build/registry/__tests__/templates-tree.test.mjs +367 -0
  342. package/scripts/build/registry/__tests__/write-places.test.mjs +425 -0
  343. package/scripts/build/registry/config.mjs +6 -65
  344. package/scripts/build/registry/discovery/icons.mjs +498 -43
  345. package/scripts/build/registry/discovery/templates.mjs +1 -1
  346. package/scripts/build/registry/generators/billing-registry.mjs +1 -1
  347. package/scripts/build/registry/generators/docs-registry.mjs +3 -4
  348. package/scripts/build/registry/generators/feature-registry.mjs +1 -1
  349. package/scripts/build/registry/generators/permissions-registry.mjs +2 -2
  350. package/scripts/build/registry/generators/template-registry.mjs +65 -49
  351. package/scripts/build/registry/index.mjs +1 -2
  352. package/scripts/build/registry/post-build/index.mjs +1 -1
  353. package/scripts/build/registry/post-build/own-gitignores.mjs +220 -0
  354. package/scripts/build/registry/post-build/page-generator.mjs +512 -268
  355. package/scripts/build/registry/post-build/route-cleanup.mjs +16 -13
  356. package/scripts/build/registry/post-build/test-fixtures.mjs +26 -8
  357. package/scripts/build/registry/project-mode.mjs +76 -0
  358. package/scripts/build/registry/shared/typescript-compiler.mjs +77 -0
  359. package/scripts/build/registry/validate-env.test.mjs +12 -8
  360. package/scripts/build/registry/watch.mjs +3 -53
  361. package/scripts/build/registry/write-places.mjs +228 -0
  362. package/scripts/build/registry.mjs +53 -30
  363. package/scripts/build/safe-fs.mjs +279 -0
  364. package/scripts/build/templates-plan.mjs +44 -0
  365. package/scripts/build/theme.mjs +46 -42
  366. package/scripts/build/update-tsconfig.mjs +16 -15
  367. package/scripts/db/cluster-changes.mjs +205 -0
  368. package/scripts/db/connection-time-limits.mjs +53 -0
  369. package/scripts/db/inspect-server.mjs +108 -0
  370. package/scripts/db/migration-time-limit.mjs +695 -0
  371. package/scripts/db/run-migrations.mjs +46 -41
  372. package/scripts/db/ssl-config.mjs +194 -0
  373. package/scripts/db/theme-location.mjs +69 -0
  374. package/scripts/db/verify-tables.mjs +3 -8
  375. package/scripts/db/verify-teams.mjs +2 -6
  376. package/scripts/db/verify-theme-migrations.mjs +169 -0
  377. package/scripts/maintenance/core-updater.mjs +1003 -0
  378. package/scripts/maintenance/step-guard.mjs +74 -0
  379. package/scripts/maintenance/update-core.mjs +14 -831
  380. package/scripts/utils/console-guard.mjs +13 -0
  381. package/scripts/utils/generated-tag.mjs +66 -0
  382. package/scripts/utils/index.mjs +9 -1
  383. package/scripts/utils/logging.mjs +140 -0
  384. package/templates/app/(auth)/accept-invite/[token]/page.tsx +4 -3
  385. package/templates/app/(auth)/verify-email/page.tsx +4 -3
  386. package/templates/app/(public)/docs/[section]/[page]/page.tsx +11 -0
  387. package/templates/app/api/auth/[...all]/route.ts +15 -14
  388. package/templates/app/api/internal/user-metadata/route.ts +6 -8
  389. package/templates/app/api/user/plan-flags/route.ts +1 -1
  390. package/templates/app/api/user/profile/route.ts +12 -17
  391. package/templates/app/api/v1/api-keys/route.ts +1 -1
  392. package/templates/app/api/v1/auth/signup-with-invite/route.ts +2 -1
  393. package/templates/app/api/v1/billing/cancel/route.ts +1 -1
  394. package/templates/app/api/v1/billing/change-plan/route.ts +1 -1
  395. package/templates/app/api/v1/billing/check-action/route.ts +1 -1
  396. package/templates/app/api/v1/billing/checkout/route.ts +1 -1
  397. package/templates/app/api/v1/blocks/validate/route.ts +1 -1
  398. package/templates/app/api/v1/media/[id]/tags/route.ts +1 -1
  399. package/templates/app/api/v1/post-categories/[id]/route.ts +1 -1
  400. package/templates/app/api/v1/post-categories/route.ts +1 -1
  401. package/templates/app/api/v1/teams/[teamId]/members/route.ts +2 -1
  402. package/templates/app/api/v1/teams/[teamId]/subscription/route.ts +3 -5
  403. package/templates/app/api/v1/teams/docs.md +4 -9
  404. package/templates/app/api/v1/teams/switch/route.ts +1 -1
  405. package/templates/app/api/v1/users/[id]/meta/[key]/route.ts +1 -1
  406. package/templates/app/api/v1/users/[id]/route.ts +1 -1
  407. package/templates/app/api/v1/users/route.ts +1 -1
  408. package/templates/app/dashboard/(main)/media/page.tsx +3 -1
  409. package/templates/app/dashboard/settings/api-keys/page.tsx +5 -4
  410. package/templates/app/dashboard/settings/profile/page.tsx +3 -2
  411. package/templates/app/devtools/scheduled-actions/page.tsx +2 -1
  412. package/templates/app/superadmin/docs/[section]/[page]/page.tsx +16 -0
  413. package/templates/app/superadmin/subscriptions/page.tsx +3 -2
  414. package/templates/app/superadmin/teams/[teamId]/page.tsx +5 -4
  415. package/templates/app/superadmin/users/[userId]/page.tsx +2 -1
  416. package/templates/app/superadmin/users/page.tsx +2 -1
  417. package/templates/blocks/cta-section/component.tsx +3 -2
  418. package/templates/blocks/cta-section/schema.ts +1 -1
  419. package/templates/blocks/features-grid/component.tsx +2 -1
  420. package/templates/blocks/features-grid/schema.ts +1 -1
  421. package/templates/blocks/hero/component.tsx +3 -2
  422. package/templates/blocks/hero/schema.ts +1 -1
  423. package/templates/blocks/testimonials/component.tsx +2 -1
  424. package/templates/blocks/testimonials/schema.ts +1 -1
  425. package/templates/blocks/text-content/component.tsx +2 -1
  426. package/templates/blocks/text-content/schema.ts +1 -1
  427. package/templates/ci-workflows/README.md +1 -1
  428. package/templates/ci-workflows/github/cypress-regression.yml +1 -1
  429. package/templates/ci-workflows/github/cypress-smoke.yml +1 -1
  430. package/templates/contents/plugins/starter/plugin/api/example/route.ts.template +1 -1
  431. package/templates/contents/themes/starter/blocks/cta-section/component.tsx +3 -2
  432. package/templates/contents/themes/starter/blocks/cta-section/schema.ts +1 -1
  433. package/templates/contents/themes/starter/blocks/features-grid/component.tsx +2 -1
  434. package/templates/contents/themes/starter/blocks/features-grid/schema.ts +1 -1
  435. package/templates/contents/themes/starter/blocks/hero/component.tsx +3 -2
  436. package/templates/contents/themes/starter/blocks/hero/schema.ts +1 -1
  437. package/templates/contents/themes/starter/blocks/testimonials/component.tsx +3 -2
  438. package/templates/contents/themes/starter/blocks/testimonials/schema.ts +1 -1
  439. package/templates/contents/themes/starter/blocks/text-content/component.tsx +2 -1
  440. package/templates/contents/themes/starter/blocks/text-content/schema.ts +1 -1
  441. package/templates/contents/themes/starter/entities/posts/components/post-header.tsx +2 -1
  442. package/templates/contents/themes/starter/lib/hooks/useAnalyticsData.ts +2 -1
  443. package/templates/contents/themes/starter/lib/hooks/useTaskStats.ts +2 -1
  444. package/templates/eslint.config.mjs +133 -9
  445. package/templates/features/blog/blocks/post-content/component.tsx +2 -1
  446. package/templates/features/blog/blocks/post-content/schema.ts +1 -1
  447. package/templates/features/blog/entities/posts/components/post-header.tsx +2 -1
  448. package/templates/features/pages/blocks/hero/component.tsx +3 -2
  449. package/templates/features/pages/blocks/hero/schema.ts +1 -1
  450. package/templates/next.config.mjs +50 -29
  451. package/templates/proxy.ts +100 -21
  452. package/templates/public/sw.js +2 -2
  453. package/templates/scripts/cy-run-prod.cjs +5 -5
  454. package/tests/jest/__mocks__/@nextsparkjs/registries/template-registry.client.ts +11 -0
  455. package/tests/jest/__mocks__/next-server.js +10 -0
  456. package/scripts/build/docs.mjs +0 -392
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Guards the console of the process that imports it, as `guardConsole` does.
3
+ * The scripts that run the registry build import it before anything else:
4
+ * modules print as they load - config.mjs has dotenv read the project's .env,
5
+ * which logs the path it read - and an import runs before the body of the
6
+ * module that imports it.
7
+ *
8
+ * @module core/scripts/utils/console-guard
9
+ */
10
+
11
+ import { guardConsole } from './logging.mjs'
12
+
13
+ guardConsole()
@@ -0,0 +1,66 @@
1
+ /**
2
+ * The generated tag `nextspark sync:app` puts on the files it writes, read here
3
+ * for the build steps that rewrite part of such a file. The format and what it
4
+ * means are the CLI's (packages/cli/src/utils/generated-tag.ts):
5
+ *
6
+ * /* @nextspark-generated core@<version> path=<path> sha256=<hash of the rest> *\/
7
+ *
8
+ * The path runs up to the ` sha256=` that ends it, and is a JSON string when the
9
+ * CLI had to quote it. On the first line, or the second after a shebang. While the hash matches, the
10
+ * file is core's to update; a rewrite that leaves a stale hash makes sync treat
11
+ * the file as changed by the project and stop updating it.
12
+ */
13
+
14
+ import { createHash } from 'node:crypto'
15
+
16
+ const TAG_LINE = /^(?:\/\/|\/\*) @nextspark-generated core@\S+(?: path=.+?)? sha256=([0-9a-f]{64})(?: \*\/)?$/
17
+
18
+ /**
19
+ * The hash a tag records: of the text below the tag, with CRLF line endings
20
+ * read as LF, so a checkout that converts line endings keeps its tags intact.
21
+ */
22
+ export function generatedHash(text) {
23
+ return createHash('sha256').update(text.replace(/\r\n/g, '\n')).digest('hex')
24
+ }
25
+
26
+ /**
27
+ * A file split around its generated tag, or null when it has none.
28
+ *
29
+ * @param {string} text
30
+ * @returns {{ head: string, line: string, body: string, intact: boolean } | null}
31
+ * `head` is the shebang line before the tag, if any; `line` the tag line with
32
+ * its line ending; `body` the file without the tag line; `intact` whether the
33
+ * body still hashes to what the tag recorded
34
+ */
35
+ export function splitGeneratedTag(text) {
36
+ const shebangEnd = text.startsWith('#!') ? text.indexOf('\n') : -1
37
+ const head = text.slice(0, shebangEnd + 1)
38
+ const newline = text.indexOf('\n', head.length)
39
+ const lineEnd = newline === -1 ? text.length : newline + 1
40
+
41
+ const match = TAG_LINE.exec(text.slice(head.length, newline === -1 ? text.length : newline).replace(/\r$/, ''))
42
+ if (!match) return null
43
+
44
+ const body = head + text.slice(lineEnd)
45
+ return { head, line: text.slice(head.length, lineEnd), body, intact: generatedHash(body) === match[1] }
46
+ }
47
+
48
+ /**
49
+ * `text` with what is below its generated tag passed through `rewrite`. A tag
50
+ * that matched the file before is given the hash of the rewritten content, so
51
+ * the file stays core's to update; a tag that no longer matched - the project
52
+ * changed the file - is kept as it was. A file with no tag is rewritten whole.
53
+ *
54
+ * @param {string} text
55
+ * @param {(body: string) => string} rewrite - Receives and returns the file without its tag line
56
+ */
57
+ export function rewriteBelowGeneratedTag(text, rewrite) {
58
+ const tag = splitGeneratedTag(text)
59
+ if (!tag) return rewrite(text)
60
+
61
+ const body = rewrite(tag.body)
62
+ let line = tag.intact ? tag.line.replace(/sha256=[0-9a-f]{64}/, `sha256=${generatedHash(body)}`) : tag.line
63
+ if (!line.endsWith('\n') && body.length > tag.head.length) line += '\n'
64
+
65
+ return tag.head + line + body.slice(tag.head.length)
66
+ }
@@ -13,7 +13,15 @@ export {
13
13
  log,
14
14
  verbose,
15
15
  setVerboseMode,
16
- isVerbose
16
+ isVerbose,
17
+ shownPath,
18
+ shownLine,
19
+ jsonLine,
20
+ guardConsole,
21
+ errorWithLines,
22
+ messageLines,
23
+ stackLines,
24
+ logFailure
17
25
  } from './logging.mjs'
18
26
 
19
27
  export {
@@ -4,6 +4,8 @@
4
4
  * @module core/scripts/utils/logging
5
5
  */
6
6
 
7
+ import { format } from 'node:util'
8
+
7
9
  // Verbose mode state (set via setVerboseMode)
8
10
  let verboseMode = false
9
11
 
@@ -25,6 +27,144 @@ export function isVerbose() {
25
27
  return verboseMode
26
28
  }
27
29
 
30
+ /**
31
+ * What breaks a line in a terminal or a log, or reorders how it reads: C0 and C1
32
+ * controls - a newline, a carriage return, ESC and the sequences it starts - DEL,
33
+ * the line and paragraph separators, and the bidirectional marks, embeddings,
34
+ * overrides and isolates.
35
+ */
36
+ const BREAKS_A_LINE = /[\u0000-\u001f\u007f-\u009f\u061c\u200e\u200f\u2028\u2029\u202a-\u202e\u2066-\u2069]/
37
+
38
+ /**
39
+ * Text as a line of output shows it: as it is, or, when it holds a character
40
+ * that breaks or reorders the line, quoted, with each such character escaped -
41
+ * the way `nextspark` shows one, which repeats these lines. JSON escapes the C0
42
+ * controls but writes the rest as they are.
43
+ *
44
+ * @param {string} path - The text to show
45
+ * @returns {string}
46
+ */
47
+ export function shownPath(path) {
48
+ if (!BREAKS_A_LINE.test(path)) return path
49
+ return JSON.stringify(path).replace(new RegExp(BREAKS_A_LINE.source, 'g'), character =>
50
+ `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`
51
+ )
52
+ }
53
+
54
+ /**
55
+ * What one call to the console prints, as a line of output shows it. The
56
+ * newlines and spaces it starts with and the newlines it ends with are kept, as
57
+ * the blank lines around it and its indent; when what is between them holds a
58
+ * character that breaks or reorders a line, all of it is shown the way
59
+ * `shownPath` shows a path, on the one line. A
60
+ * newline inside a call can't be told from one in a name the call prints, so
61
+ * what spans lines is printed one call per line, and a call starts with its own
62
+ * text rather than with a name.
63
+ *
64
+ * @param {string} text - What one call prints
65
+ * @returns {string}
66
+ */
67
+ export function shownLine(text) {
68
+ const [, before, body, after] = /^([\n ]*)([\s\S]*?)(\n*)$/.exec(text)
69
+ return `${before}${shownPath(body)}${after}`
70
+ }
71
+
72
+ /**
73
+ * `value` as JSON that a line of output shows as it is: JSON.stringify escapes
74
+ * the C0 controls but leaves the C1 controls, the separators and the
75
+ * bidirectional marks as they are, and those are valid JSON escaped too.
76
+ *
77
+ * @param {unknown} value - What to write as JSON
78
+ * @returns {string}
79
+ */
80
+ export function jsonLine(value) {
81
+ return JSON.stringify(value).replace(new RegExp(BREAKS_A_LINE.source, 'g'), character =>
82
+ `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`
83
+ )
84
+ }
85
+
86
+ const GUARDED = Symbol.for('nextspark.shownLine')
87
+
88
+ /**
89
+ * Make each call to `target`'s log, info, warn, error and debug print what it
90
+ * formats the way `shownLine` shows it. Once this runs, whatever prints through
91
+ * the console - the build's own lines, the paths and names in them, and the
92
+ * libraries it loads, dotenv among them - is escaped there, where it is printed.
93
+ *
94
+ * @param {Console} [target] - The console to guard
95
+ */
96
+ export function guardConsole(target = console) {
97
+ for (const method of ['log', 'info', 'warn', 'error', 'debug']) {
98
+ const original = target[method]
99
+ if (typeof original !== 'function' || original[GUARDED]) continue
100
+ const guarded = (...args) => original.call(target, shownLine(format(...args)))
101
+ guarded[GUARDED] = true
102
+ target[method] = guarded
103
+ }
104
+ }
105
+
106
+ /**
107
+ * An error whose message is `lines`, one per line. The build prints an error's
108
+ * message one line per call, and takes as lines of their own only the ones an
109
+ * error carries this way: a newline anywhere else in a message belongs to a
110
+ * name in it.
111
+ *
112
+ * @param {string[]} lines - The lines of the message
113
+ * @returns {Error}
114
+ */
115
+ export function errorWithLines(lines) {
116
+ return Object.assign(new Error(lines.join('\n')), { lines })
117
+ }
118
+
119
+ /**
120
+ * The lines of an error's message, each printed with a call of its own: the
121
+ * ones `errorWithLines` gave it, or else the whole message as one.
122
+ *
123
+ * @param {unknown} error - What was thrown
124
+ * @returns {string[]}
125
+ */
126
+ export function messageLines(error) {
127
+ if (Array.isArray(error?.lines) && error.lines.every(line => typeof line === 'string')) return error.lines
128
+ return [typeof error?.message === 'string' ? error.message : String(error)]
129
+ }
130
+
131
+ /**
132
+ * The lines of an error's stack, each printed with a call of its own: its
133
+ * heading with the message as `messageLines` splits it, and then each frame -
134
+ * split where the next ` at ` starts, since a frame names a file whose path
135
+ * can hold a newline of its own.
136
+ *
137
+ * @param {unknown} error - What was thrown
138
+ * @returns {string[]}
139
+ */
140
+ export function stackLines(error) {
141
+ const stack = typeof error?.stack === 'string' ? error.stack : String(error)
142
+ const message = typeof error?.message === 'string' ? error.message : ''
143
+ const at = message ? stack.indexOf(message) : -1
144
+ if (at === -1) return stack.split(/\n(?= {4}at )/)
145
+ const [first, ...rest] = messageLines(error)
146
+ const frames = stack.slice(at + message.length).replace(/^\n/, '')
147
+ return [`${stack.slice(0, at)}${first}`, ...rest, ...(frames ? frames.split(/\n(?= {4}at )/) : [])]
148
+ }
149
+
150
+ /**
151
+ * Log that what `label` names failed with `error`: the first line of its
152
+ * message after the label, each other line of it on its own, and, with
153
+ * `withStack`, the stack on stderr, one line per call.
154
+ *
155
+ * @param {string} label - What failed
156
+ * @param {unknown} error - What was thrown
157
+ * @param {boolean} [withStack] - Whether to print the stack too
158
+ */
159
+ export function logFailure(label, error, withStack = false) {
160
+ const [first, ...rest] = messageLines(error)
161
+ log(`${label}: ${first}`, 'error')
162
+ for (const line of rest) console.log(line)
163
+ if (withStack) {
164
+ for (const line of stackLines(error)) console.error(line)
165
+ }
166
+ }
167
+
28
168
  /**
29
169
  * Log a message with an emoji prefix based on type
30
170
  *
@@ -10,6 +10,7 @@ import { toast } from 'sonner'
10
10
  import Link from 'next/link'
11
11
  import { sel } from '@nextsparkjs/core/selectors'
12
12
  import { getTemplateOrDefaultClient } from '@nextsparkjs/registries/template-registry.client'
13
+ import { withBasePath } from '@nextsparkjs/core/lib/base-path'
13
14
 
14
15
  type InvitationStatus = 'loading' | 'valid' | 'accepting' | 'accepted' | 'error' | 'expired' | 'not_found' | 'email_mismatch' | 'already_member' | 'requires_auth'
15
16
 
@@ -38,7 +39,7 @@ function AcceptInvitePage() {
38
39
  async function validateAndAccept() {
39
40
  try {
40
41
  // First validate the invitation
41
- const response = await fetch(`/api/v1/team-invitations/${token}`)
42
+ const response = await fetch(withBasePath(`/api/v1/team-invitations/${token}`))
42
43
  const data = await response.json()
43
44
 
44
45
  if (!response.ok) {
@@ -80,7 +81,7 @@ function AcceptInvitePage() {
80
81
 
81
82
  setStatus('accepting')
82
83
 
83
- const acceptResponse = await fetch(`/api/v1/team-invitations/${token}/accept`, {
84
+ const acceptResponse = await fetch(withBasePath(`/api/v1/team-invitations/${token}/accept`), {
84
85
  method: 'POST',
85
86
  credentials: 'include'
86
87
  })
@@ -125,7 +126,7 @@ function AcceptInvitePage() {
125
126
  setStatus('accepting')
126
127
 
127
128
  try {
128
- const response = await fetch(`/api/v1/team-invitations/${token}/accept`, {
129
+ const response = await fetch(withBasePath(`/api/v1/team-invitations/${token}/accept`), {
129
130
  method: 'POST',
130
131
  credentials: 'include'
131
132
  })
@@ -7,6 +7,7 @@ import { Button } from '@nextsparkjs/core/components/ui/button';
7
7
  import { Alert, AlertDescription } from '@nextsparkjs/core/components/ui/alert';
8
8
  import { getTemplateOrDefaultClient } from '@nextsparkjs/registries/template-registry.client'
9
9
  import { sel } from '@nextsparkjs/core/selectors'
10
+ import { withBasePath } from '@nextsparkjs/core/lib/base-path'
10
11
 
11
12
  function VerifyEmailContent() {
12
13
  const searchParams = useSearchParams()!;
@@ -26,7 +27,7 @@ function VerifyEmailContent() {
26
27
 
27
28
  try {
28
29
  // Call the Better Auth verify endpoint with special header to avoid redirect loop
29
- const response = await fetch(`/api/auth/verify-email?token=${token}`, {
30
+ const response = await fetch(withBasePath(`/api/auth/verify-email?token=${token}`), {
30
31
  method: 'GET',
31
32
  credentials: 'include',
32
33
  headers: {
@@ -43,7 +44,7 @@ function VerifyEmailContent() {
43
44
 
44
45
  // Create default metadata after successful verification
45
46
  try {
46
- const response = await fetch('/api/auth/session', {
47
+ const response = await fetch(withBasePath('/api/auth/get-session'), {
47
48
  method: 'GET',
48
49
  credentials: 'include'
49
50
  });
@@ -52,7 +53,7 @@ function VerifyEmailContent() {
52
53
  const session = await response.json();
53
54
  if (session?.user?.id) {
54
55
  // Create default metadata for the newly verified user
55
- await fetch('/api/internal/user-metadata', {
56
+ await fetch(withBasePath('/api/internal/user-metadata'), {
56
57
  method: 'POST',
57
58
  headers: {
58
59
  'Content-Type': 'application/json',
@@ -15,6 +15,17 @@ interface DocsPageProps {
15
15
  }>
16
16
  }
17
17
 
18
+ // generateStaticParams below lists every public doc page, and dynamicParams =
19
+ // false answers 404 for any other section/page pair before the page renders:
20
+ // in `next dev`, and in a production build that prerenders this route, which
21
+ // it does when the app's locale is fixed (see isLocaleFixed). An app that reads
22
+ // the locale from the request renders the route on demand, where Next has no
23
+ // prerendered list to check, and the notFound() calls below cannot set the
24
+ // status either: they run inside the layouts' Suspense boundaries, after the
25
+ // response head has gone out with a 200. For those requests the proxy answers
26
+ // 404 before anything renders (isMissingDocsPage in proxy.ts).
27
+ export const dynamicParams = false
28
+
18
29
  export async function generateStaticParams() {
19
30
  const params = []
20
31
 
@@ -10,6 +10,8 @@ import { wrapAuthHandlerWithCors, handleCorsPreflightRequest, addCorsHeaders } f
10
10
  import { checkDistributedRateLimit } from "@nextsparkjs/core/lib/api/rate-limit";
11
11
  import { withSignupContext } from "@nextsparkjs/core/lib/auth-context";
12
12
  import { dispatchSecurityNotificationsForRequest } from "@nextsparkjs/core/lib/auth/security-notifications";
13
+ import { verifyEmailPageUrl } from "@nextsparkjs/core/lib/auth/verify-email-link";
14
+ import { withBasePathRequest } from "@nextsparkjs/core/lib/base-path";
13
15
 
14
16
  const handlers = toNextJsHandler(auth);
15
17
 
@@ -28,16 +30,9 @@ export async function GET(req: NextRequest, context: { params: Promise<{ all: st
28
30
  const isFromUI = req.headers.get('x-verify-from-ui') === 'true';
29
31
 
30
32
  if (pathname === '/api/auth/verify-email' && !isFromUI) {
31
- const token = req.nextUrl.searchParams.get('token');
32
- const callbackURL = req.nextUrl.searchParams.get('callbackURL');
33
-
34
- if (token) {
35
- // This is from an email link, redirect to the UI verification page
36
- const redirectUrl = new URL('/verify-email', req.url);
37
- redirectUrl.searchParams.set('token', token);
38
- if (callbackURL) {
39
- redirectUrl.searchParams.set('callbackURL', callbackURL);
40
- }
33
+ // This is from an email link, redirect to the UI verification page
34
+ const redirectUrl = verifyEmailPageUrl(req.url);
35
+ if (redirectUrl) {
41
36
  return NextResponse.redirect(redirectUrl);
42
37
  }
43
38
  }
@@ -56,11 +51,14 @@ export async function GET(req: NextRequest, context: { params: Promise<{ all: st
56
51
  ? (req.cookies.get('signup-intent')?.value || undefined)
57
52
  : undefined;
58
53
 
54
+ // Better Auth matches its routes with the base path in the URL
55
+ const authReq = withBasePathRequest(req);
56
+
59
57
  // Wrap with CORS headers for cross-origin requests (mobile apps, etc.)
60
58
  return wrapAuthHandlerWithCors(
61
59
  signupIntent
62
- ? () => withSignupContext({ signupIntent }, () => handlers.GET(req))
63
- : () => handlers.GET(req),
60
+ ? () => withSignupContext({ signupIntent }, () => handlers.GET(authReq))
61
+ : () => handlers.GET(authReq),
64
62
  req
65
63
  );
66
64
  }
@@ -188,11 +186,14 @@ export async function POST(req: NextRequest) {
188
186
  // handlers.POST(req) reads req's body exactly once.
189
187
  const securityReq = req.clone() as NextRequest;
190
188
 
189
+ // Better Auth matches its routes with the base path in the URL
190
+ const authReq = withBasePathRequest(req);
191
+
191
192
  // Wrap with CORS headers for cross-origin requests (mobile apps, etc.)
192
193
  const response = await wrapAuthHandlerWithCors(
193
194
  signupIntent
194
- ? () => withSignupContext({ signupIntent }, () => handlers.POST(req))
195
- : () => handlers.POST(req),
195
+ ? () => withSignupContext({ signupIntent }, () => handlers.POST(authReq))
196
+ : () => handlers.POST(authReq),
196
197
  req
197
198
  );
198
199
 
@@ -28,16 +28,14 @@ export const POST = withRateLimitTier(async (req: NextRequest) => {
28
28
  return NextResponse.json({ error: 'Metadata is required' }, { status: 400 })
29
29
  }
30
30
 
31
- // Crear cada grupo de metadata por separado
32
- for (const [metaKey, metaValue] of Object.entries(metadata)) {
33
- if (metaValue && typeof metaValue === 'object') {
34
- await MetaService.setEntityMeta('user', userId, metaKey, metaValue, userId)
35
- }
36
- }
31
+ // Defaults only fill in what is missing. The caller picks them from a read
32
+ // of the user's meta that may be stale by now, so a preference saved in
33
+ // between (a theme change, a collapsed sidebar) is kept.
34
+ await MetaService.mergeEntityMetaGroups('user', userId, metadata, userId, { defaults: true })
37
35
 
38
- return NextResponse.json({
36
+ return NextResponse.json({
39
37
  success: true,
40
- message: 'Default metadata created successfully'
38
+ message: 'Default metadata created successfully'
41
39
  })
42
40
  } catch (error) {
43
41
  // Log error for debugging but don't expose details to client
@@ -8,7 +8,7 @@
8
8
  import { NextRequest, NextResponse } from 'next/server'
9
9
  import { getTypedSession } from '@nextsparkjs/core/lib/auth'
10
10
  import { getUserPlanAndFlags, updateUserPlan, updateUserFlags } from '@nextsparkjs/core/lib/user-data'
11
- import { z } from 'zod'
11
+ import * as z from 'zod'
12
12
  import type { UserRole } from '@nextsparkjs/core/types/user.types'
13
13
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
14
14
 
@@ -3,7 +3,7 @@ import { auth } from '@nextsparkjs/core/lib/auth'
3
3
  import { headers } from 'next/headers'
4
4
  import { queryOneWithRLS, mutateWithRLS, queryOne } from '@nextsparkjs/core/lib/db'
5
5
  import { profileSchema } from '@nextsparkjs/core/lib/validation'
6
- import { MetaService } from '@nextsparkjs/core/lib/services/meta.service'
6
+ import { MetaService, MetaValueTooLargeError } from '@nextsparkjs/core/lib/services/meta.service'
7
7
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
8
8
 
9
9
  export const GET = withRateLimitTier(async (request: NextRequest) => {
@@ -68,15 +68,12 @@ export const PATCH = withRateLimitTier(async (request: NextRequest) => {
68
68
  const body = await request.json()
69
69
  const { meta, ...profileData } = body
70
70
 
71
- // Handle metadata-only updates (formato anidado)
71
+ // Handle metadata-only updates (nested format)
72
72
  if (meta && Object.keys(profileData).length === 0) {
73
- // Procesar cada grupo de metadata por separado
74
- for (const [metaKey, metaValue] of Object.entries(meta)) {
75
- if (metaValue && typeof metaValue === 'object') {
76
- await MetaService.setEntityMeta('user', session.user.id, metaKey, metaValue, session.user.id)
77
- }
78
- }
79
-
73
+ // Each group (uiPreferences, ...) is merged into the stored one: the
74
+ // theme toggle sends only `theme`, the sidebar only `sidebarCollapsed`.
75
+ await MetaService.mergeEntityMetaGroups('user', session.user.id, meta, session.user.id)
76
+
80
77
  return NextResponse.json({
81
78
  message: 'Settings updated successfully',
82
79
  success: true
@@ -113,21 +110,19 @@ export const PATCH = withRateLimitTier(async (request: NextRequest) => {
113
110
  }
114
111
  }
115
112
 
116
- // Handle metadata updates if provided (formato anidado)
113
+ // Handle metadata updates if provided (nested format), merged like above
117
114
  if (meta) {
118
- // Procesar cada grupo de metadata por separado
119
- for (const [metaKey, metaValue] of Object.entries(meta)) {
120
- if (metaValue && typeof metaValue === 'object') {
121
- await MetaService.setEntityMeta('user', session.user.id, metaKey, metaValue, session.user.id)
122
- }
123
- }
115
+ await MetaService.mergeEntityMetaGroups('user', session.user.id, meta, session.user.id)
124
116
  }
125
-
117
+
126
118
  return NextResponse.json({
127
119
  message: 'Profile updated successfully',
128
120
  success: true
129
121
  })
130
122
  } catch (error) {
123
+ if (error instanceof MetaValueTooLargeError) {
124
+ return NextResponse.json({ error: error.message }, { status: 413 })
125
+ }
131
126
  console.error('Error updating user profile:', error)
132
127
  return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
133
128
  }
@@ -11,7 +11,7 @@ import { authenticateRequest, createAuthFailureResponse, resolveTeamContext } fr
11
11
  import { ApiKeyManager, API_SCOPES, API_KEY_LIMITS } from '@nextsparkjs/core/lib/api/keys';
12
12
  import { validateScopesForUser } from '@nextsparkjs/core/lib/api/auth';
13
13
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit';
14
- import { z } from 'zod';
14
+ import * as z from 'zod';
15
15
 
16
16
  const createApiKeySchema = z.object({
17
17
  name: z.string().min(1, 'Name is required').max(API_KEY_LIMITS.maxKeyNameLength, 'Name too long'),
@@ -12,6 +12,7 @@ import type { TeamInvitation, TeamMember } from '@nextsparkjs/core/lib/teams/typ
12
12
  import { I18N_CONFIG } from '@nextsparkjs/core/lib/config'
13
13
  import { withSignupContext } from '@nextsparkjs/core/lib/auth-context'
14
14
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
15
+ import { withBasePath } from '@nextsparkjs/core/lib/base-path'
15
16
 
16
17
  // Handle CORS preflight
17
18
  export async function OPTIONS(request: NextRequest) {
@@ -111,7 +112,7 @@ export const POST = withRateLimitTier(withApiLogging(
111
112
  // Step 2: Create user using Better Auth's internal API
112
113
  // Wrap in signup context to skip automatic team creation
113
114
  // (user will be added to the invited team instead)
114
- const signUpRequest = new Request(`${process.env.NEXT_PUBLIC_APP_URL}/api/auth/sign-up/email`, {
115
+ const signUpRequest = new Request(`${process.env.NEXT_PUBLIC_APP_URL}${withBasePath('/api/auth/sign-up/email')}`, {
115
116
  method: 'POST',
116
117
  headers: {
117
118
  'Content-Type': 'application/json',
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import { NextRequest, NextResponse } from 'next/server'
11
- import { z } from 'zod'
11
+ import * as z from 'zod'
12
12
  import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
13
13
  import { SubscriptionService, MembershipService } from '@nextsparkjs/core/lib/services'
14
14
  import { getBillingGateway } from '@nextsparkjs/core/lib/billing/gateways/factory'
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import { NextRequest, NextResponse } from 'next/server'
11
- import { z } from 'zod'
11
+ import * as z from 'zod'
12
12
  import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
13
13
  import { SubscriptionService, MembershipService } from '@nextsparkjs/core/lib/services'
14
14
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
@@ -12,7 +12,7 @@
12
12
  import { NextRequest, NextResponse } from 'next/server'
13
13
  import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
14
14
  import { SubscriptionService } from '@nextsparkjs/core/lib/services'
15
- import { z } from 'zod'
15
+ import * as z from 'zod'
16
16
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
17
17
 
18
18
  const checkActionSchema = z.object({
@@ -11,7 +11,7 @@ import { NextRequest, NextResponse } from 'next/server'
11
11
  import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
12
12
  import { getBillingGateway } from '@nextsparkjs/core/lib/billing/gateways/factory'
13
13
  import { SubscriptionService, MembershipService } from '@nextsparkjs/core/lib/services'
14
- import { z } from 'zod'
14
+ import * as z from 'zod'
15
15
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
16
16
 
17
17
  const checkoutSchema = z.object({
@@ -1,6 +1,6 @@
1
1
  import { NextRequest, NextResponse } from 'next/server'
2
2
  import { BLOCK_REGISTRY } from '@nextsparkjs/registries/block-registry'
3
- import { z } from 'zod'
3
+ import * as z from 'zod'
4
4
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
5
5
 
6
6
  const requestSchema = z.object({
@@ -5,7 +5,7 @@ import { API_ERROR_CODES } from '@nextsparkjs/core/lib/api/api-error'
5
5
  import { checkPermission } from '@nextsparkjs/core/lib/permissions/check'
6
6
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
7
7
  import { MediaService } from '@nextsparkjs/core/lib/services/media.service'
8
- import { z } from 'zod'
8
+ import * as z from 'zod'
9
9
 
10
10
  const addTagSchema = z.object({
11
11
  tagId: z.string().min(1),
@@ -1,7 +1,7 @@
1
1
  import { NextRequest, NextResponse } from 'next/server'
2
2
  import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
3
3
  import { query as dbQuery } from '@nextsparkjs/core/lib/db'
4
- import { z } from 'zod'
4
+ import * as z from 'zod'
5
5
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
6
6
 
7
7
  const updateCategorySchema = z.object({
@@ -1,7 +1,7 @@
1
1
  import { NextRequest, NextResponse } from 'next/server'
2
2
  import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
3
3
  import { query as dbQuery } from '@nextsparkjs/core/lib/db'
4
- import { z } from 'zod'
4
+ import * as z from 'zod'
5
5
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
6
6
 
7
7
  const createCategorySchema = z.object({
@@ -19,6 +19,7 @@ import type { TeamMember, TeamInvitation, TeamRole, Team } from '@nextsparkjs/co
19
19
  import { EmailFactory } from '@nextsparkjs/core/lib/email/factory'
20
20
  import { sendTeamInvitationEmail } from '@nextsparkjs/core/lib/email/send'
21
21
  import { I18N_CONFIG } from '@nextsparkjs/core/lib/config'
22
+ import { withBasePath } from '@nextsparkjs/core/lib/base-path'
22
23
 
23
24
  // Handle CORS preflight
24
25
  export async function OPTIONS(request: NextRequest) {
@@ -294,7 +295,7 @@ export const POST = withRateLimitTier(withApiLogging(
294
295
 
295
296
  // Build accept URL
296
297
  const baseUrl = (process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:5173').replace(/\/$/, '')
297
- const acceptUrl = `${baseUrl}/accept-invite/${token}`
298
+ const acceptUrl = `${baseUrl}${withBasePath(`/accept-invite/${token}`)}`
298
299
 
299
300
  // Send invitation email
300
301
  try {
@@ -41,11 +41,9 @@ export const GET = withRateLimitTier(async function GET(request: NextRequest, pr
41
41
 
42
42
  const subscription = await SubscriptionService.getActive(teamId)
43
43
 
44
- if (!subscription) {
45
- return createApiError('No active subscription found for this team', 404)
46
- }
47
-
48
- return createApiResponse({ subscription })
44
+ // A team can legitimately have no subscription yet. Keep that normal state
45
+ // in the successful response so dashboard loads do not log a 404.
46
+ return createApiResponse({ subscription: subscription ?? null })
49
47
  } catch (error) {
50
48
  console.error('[Billing API] Error fetching subscription:', error)
51
49
  return createApiError('Failed to fetch subscription', 500)