@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,205 @@
1
+ // What a theme verification run changes outside the database it was given.
2
+ //
3
+ // A migration run is not contained in its database: 001 creates the
4
+ // `authenticated`, `anon` and `service_role` roles, and 022 creates
5
+ // `nextspark_app`, sets it to INHERIT and grants it `authenticated` plus
6
+ // membership to the connecting user. Roles are cluster-wide, so those
7
+ // statements reach every other database on the same Postgres server, including
8
+ // ones the run was never pointed at.
9
+ //
10
+ // The database being empty says nothing about that, which is why the checks
11
+ // here look at the cluster: the roles the migrations touch, and whether any
12
+ // other database is using this server.
13
+
14
+ /**
15
+ * Roles the core migrations create or alter, and what they do to each.
16
+ * `altered` separates the one whose attributes and memberships the migrations
17
+ * change even when it is already there from the ones a Supabase project
18
+ * already has and 001 only fills in.
19
+ */
20
+ export const GLOBAL_OBJECTS = [
21
+ { role: 'authenticated', change: 'created if missing', altered: false },
22
+ { role: 'anon', change: 'created if missing', altered: false },
23
+ { role: 'service_role', change: 'created if missing', altered: false },
24
+ {
25
+ role: 'nextspark_app',
26
+ change: 'created if missing, set to INHERIT, granted authenticated',
27
+ altered: true,
28
+ },
29
+ {
30
+ role: 'current_user',
31
+ change: 'granted nextspark_app, so whoever runs this can SET ROLE to it',
32
+ altered: true,
33
+ connecting: true,
34
+ },
35
+ ]
36
+
37
+ // `current_user` is whoever connects, so it is announced but never looked for
38
+ // among the roles the server already has.
39
+ const ALTERED_ROLES = new Set(
40
+ GLOBAL_OBJECTS.filter(object => object.altered && !object.connecting).map(object => object.role)
41
+ )
42
+
43
+ /**
44
+ * Databases a Postgres server creates for itself, or a managed one adds. Their
45
+ * presence says nothing about the server being in use — `postgres` is asked
46
+ * about separately, since a hosted project can keep the app's own schema there.
47
+ *
48
+ * Only `template0` and `template1` among templates: any database can be marked
49
+ * `datistemplate`, and one a user marked that way shares the cluster's roles
50
+ * like any other.
51
+ */
52
+ const HOUSEKEEPING_DATABASES = new Set([
53
+ 'postgres', 'template0', 'template1', 'rdsadmin', 'azure_maintenance', 'azure_sys', 'cloudsqladmin',
54
+ ])
55
+
56
+ /** The database a client connects to when it only needs the server. */
57
+ export const MAINTENANCE_DATABASE = 'postgres'
58
+
59
+ export const ROLES_SQL = `
60
+ SELECT r.rolname AS name,
61
+ r.rolcanlogin AS can_login,
62
+ COALESCE(array_agg(g.rolname) FILTER (WHERE g.rolname IS NOT NULL), '{}'::text[]) AS member_of
63
+ FROM pg_roles r
64
+ LEFT JOIN pg_auth_members m ON m.member = r.oid
65
+ LEFT JOIN pg_roles g ON g.oid = m.roleid
66
+ WHERE r.rolname IN ('authenticated', 'anon', 'service_role')
67
+ OR r.rolname LIKE 'nextspark\\_%'
68
+ GROUP BY r.rolname, r.rolcanlogin
69
+ ORDER BY r.rolname
70
+ `
71
+
72
+ // A database that refuses connections (`datallowconn = false`) or is marked as
73
+ // a template is still a database on this server, sharing the roles this run
74
+ // alters, so it counts. The server's own templates are left out by name, in
75
+ // HOUSEKEEPING_DATABASES.
76
+ export const DATABASES_SQL = `
77
+ SELECT datname AS name
78
+ FROM pg_database
79
+ WHERE datname <> current_database()
80
+ ORDER BY datname
81
+ `
82
+
83
+ /** An array of role names, whether the driver hands over an array or `{a,b}`. */
84
+ function asList(value) {
85
+ if (Array.isArray(value)) return value
86
+ if (typeof value !== 'string') return []
87
+ return value.replace(/^\{|\}$/g, '').split(',').filter(Boolean)
88
+ }
89
+
90
+ /**
91
+ * What the run would change beyond its own database, and whether the cluster
92
+ * shows signs of being used by anything else.
93
+ *
94
+ * A role the migrations touch that already exists is the stronger signal: the
95
+ * run alters it for whoever else is using it. Another database on the server is
96
+ * the weaker one, and enough on its own — a role created now lands in a cluster
97
+ * that is not this run's to change.
98
+ *
99
+ * `maintenance` is what looking at the `postgres` database answered:
100
+ * `{ objects }` when it could be read, `{ unreachable: true, reason }` when it
101
+ * could not. Not being able to look is itself a reason to refuse — a server
102
+ * that denies CONNECT to its own maintenance database is a managed one with
103
+ * someone else's rules on it, not a container this run may rearrange.
104
+ */
105
+ export function inspectCluster({ roles = [], databases = [], maintenance = {} } = {}) {
106
+ const maintenanceObjects = maintenance.objects ?? []
107
+ const existingRoles = roles.map(role => ({
108
+ name: role.name,
109
+ canLogin: role.can_login ?? role.canLogin ?? false,
110
+ memberOf: asList(role.member_of ?? role.memberOf),
111
+ }))
112
+ const otherDatabases = databases
113
+ .map(database => database.name ?? database)
114
+ .filter(name => !HOUSEKEEPING_DATABASES.has(name))
115
+
116
+ const describe = role => (role.memberOf.length ? `${role.name} (member of ${role.memberOf.join(', ')})` : role.name)
117
+ const altered = existingRoles.filter(role => ALTERED_ROLES.has(role.name) || role.name.startsWith('nextspark_'))
118
+ const shared = existingRoles.filter(role => !altered.includes(role))
119
+
120
+ const reasons = []
121
+ if (altered.length > 0) {
122
+ reasons.push(`this run alters roles that are already here: ${altered.map(describe).join(', ')}`)
123
+ }
124
+ if (shared.length > 0) {
125
+ reasons.push(
126
+ `roles these migrations create already exist, so something else set this server up: ${shared.map(describe).join(', ')}`
127
+ )
128
+ }
129
+ if (otherDatabases.length > 0) {
130
+ const shown = otherDatabases.slice(0, 5).join(', ')
131
+ const rest = otherDatabases.length > 5 ? `, and ${otherDatabases.length - 5} more` : ''
132
+ reasons.push(`other databases share this server: ${shown}${rest}`)
133
+ }
134
+ if (maintenanceObjects.length > 0) {
135
+ const examples = maintenanceObjects.slice(0, 3).map(object => object.name ?? object).join(', ')
136
+ reasons.push(`the ${MAINTENANCE_DATABASE} database holds objects of its own, for example ${examples}`)
137
+ }
138
+ if (maintenance.unreachable) {
139
+ const detail = maintenance.reason ? `: ${maintenance.reason}` : ''
140
+ reasons.push(
141
+ `the ${MAINTENANCE_DATABASE} database could not be read${detail}, so what else is on this server is unknown`
142
+ )
143
+ }
144
+
145
+ return { disposable: reasons.length === 0, reasons, existingRoles, otherDatabases }
146
+ }
147
+
148
+ /**
149
+ * Words that can stand where a role name would, in the statements above:
150
+ * GRANT's own syntax, the privileges it grants, and the objects it grants them
151
+ * on. None of them is a role.
152
+ */
153
+ const GRANT_KEYWORDS = new Set([
154
+ 'ALL', 'PRIVILEGES', 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER',
155
+ 'CREATE', 'CONNECT', 'TEMPORARY', 'TEMP', 'EXECUTE', 'USAGE', 'SET', 'ALTER', 'MAINTAIN',
156
+ 'ON', 'IN', 'SCHEMA', 'TABLE', 'TABLES', 'SEQUENCE', 'SEQUENCES', 'FUNCTION', 'FUNCTIONS',
157
+ 'ROUTINE', 'ROUTINES', 'DATABASE', 'DOMAIN', 'TYPE', 'LANGUAGE', 'PUBLIC', 'SYSTEM',
158
+ 'FOREIGN', 'DATA', 'WRAPPER', 'SERVER', 'LARGE', 'OBJECT', 'TABLESPACE', 'PARAMETER',
159
+ 'OPTION', 'ADMIN', 'INHERIT', 'GRANTED', 'BY', 'FOR', 'ROLE', 'COLUMN',
160
+ ])
161
+
162
+ /**
163
+ * Every role a migration names, whichever statement names it.
164
+ *
165
+ * Both sides of a grant count: `GRANT authenticated TO reporting` alters
166
+ * `reporting` as much as it uses `authenticated`, and a grant of privileges —
167
+ * `GRANT SELECT ON ... TO reporting` — names only the grantee. A grant can list
168
+ * several of either, so each list is split on commas.
169
+ */
170
+ export function rolesNamedIn(sql) {
171
+ const named = new Set()
172
+ // Comments and RAISE messages are prose: a GRANT quoted inside either is
173
+ // being talked about, not run. A GRANT inside format() is run, so string
174
+ // literals in general stay.
175
+ const statements = sql
176
+ .replace(/\/\*[\s\S]*?\*\//g, ' ')
177
+ .replace(/--[^\n]*/g, ' ')
178
+ .replace(/\bRAISE\s+(?:DEBUG|LOG|INFO|NOTICE|WARNING|EXCEPTION)\b[^;]*;/gi, ' ')
179
+
180
+ const add = list => {
181
+ for (const name of list.split(',')) {
182
+ // A grantee list can end inside a format() call, so the string and the
183
+ // call close on the last name: `format('GRANT x TO %I', current_user)`.
184
+ const role = name.trim().replace(/[)'"]+$/, '').replace(/^["']+/, '')
185
+ // GRANT's own keywords, and the object a privilege is granted on, are
186
+ // not roles; `format('... %I', current_user)` names the connecting user.
187
+ if (/^[a-z_]\w*$/i.test(role) && !GRANT_KEYWORDS.has(role.toUpperCase())) named.add(role)
188
+ }
189
+ }
190
+
191
+ for (const [, list] of statements.matchAll(/\b(?:CREATE|ALTER|DROP)\s+(?:ROLE|USER|GROUP)\s+(?:IF\s+(?:NOT\s+)?EXISTS\s+)?("?\w+"?)/gi)) {
192
+ add(list)
193
+ }
194
+ // The grantee list runs from the last TO/FROM to the end of the statement,
195
+ // past any WITH ADMIN OPTION / GRANTED BY tail.
196
+ for (const [, grantees] of statements.matchAll(/\b(?:GRANT|REVOKE)\b[^;]*?\s(?:TO|FROM)\s+([^;]+)/gi)) {
197
+ add(grantees.split(/\bWITH\b|\bGRANTED\s+BY\b|\bCASCADE\b|\bRESTRICT\b/i)[0])
198
+ }
199
+ // What a grant of role membership hands over, which is a role too.
200
+ for (const [, roles] of statements.matchAll(/\b(?:GRANT|REVOKE)\s+((?:"?\w+"?\s*,\s*)*"?\w+"?)\s+(?:TO|FROM)\s/gi)) {
201
+ add(roles)
202
+ }
203
+
204
+ return named
205
+ }
@@ -0,0 +1,53 @@
1
+ // Time limits on a pg connection that hold whatever the connection string says.
2
+ //
3
+ // pg reads a connection string's parameters over the options passed next to it,
4
+ // so a URL ending in `?statement_timeout=0&query_timeout=` would switch off both
5
+ // the server's limit and the client's. The client is therefore built exactly as
6
+ // pg builds one for the string, with no limits among the options, and the two
7
+ // limits are then set on the connection parameters pg resolved for it. Which of
8
+ // the string's parameters a client acts on, and which it ignores, is decided by
9
+ // the installed version of pg in the same way it would be without the limits;
10
+ // only the two limits differ. pg reads them from those parameters when it
11
+ // connects (statement_timeout, sent in the startup message) and each time it
12
+ // sends a query (query_timeout).
13
+ //
14
+ // Nothing else a connection brings along lifts the server's limit: the
15
+ // statement_timeout sent when connecting outranks one in
16
+ // `options=-c statement_timeout=…`, in PGOPTIONS, or set on the database or the
17
+ // role.
18
+
19
+ import { scriptClient } from './ssl-config.mjs';
20
+
21
+ /** The connection-string parameters pg reads over the time limits given next to them. */
22
+ export const TIME_LIMIT_PARAMETERS = ['statement_timeout', 'query_timeout'];
23
+
24
+ /** How pg builds a client for the string, with the shared application SSL policy. */
25
+ function clientFor(connectionString, options = {}) {
26
+ return scriptClient(connectionString, options);
27
+ }
28
+
29
+ /**
30
+ * The time-limit parameters the connection string sets, as pg reads them: the
31
+ * ones whose value stays the same whatever limit is passed next to the string.
32
+ */
33
+ export function timeLimitParametersIn(connectionString) {
34
+ const withLimits = limit => clientFor(connectionString, { statement_timeout: limit, query_timeout: limit }).connectionParameters;
35
+ const one = withLimits(1);
36
+ const two = withLimits(2);
37
+ return TIME_LIMIT_PARAMETERS.filter(name => one[name] === two[name]);
38
+ }
39
+
40
+ /**
41
+ * A client whose limits are the ones given: `connectMs` to connect,
42
+ * `statementMs` for the server to cancel a statement, `queryMs` for the client
43
+ * to give up on an answer. `database` connects to another database on the same
44
+ * server, as whoever the connection string names.
45
+ */
46
+ export function timeLimitedClient(connectionString, { connectMs, statementMs, queryMs }, { database } = {}) {
47
+ const client = clientFor(connectionString, { connectionTimeoutMillis: connectMs });
48
+ const parameters = client.connectionParameters;
49
+ parameters.statement_timeout = statementMs;
50
+ parameters.query_timeout = queryMs;
51
+ if (database !== undefined) client.database = parameters.database = database;
52
+ return client;
53
+ }
@@ -0,0 +1,108 @@
1
+ // What db:verify-theme asks a Postgres server before it migrates anything.
2
+ //
3
+ // Every question has a time limit, not only the connection. A query that waits
4
+ // on a lock someone else holds on a catalog, or a server that stops answering
5
+ // once the connection is up, would otherwise leave the command waiting until
6
+ // something outside kills it, when what the command owes is a refusal. The
7
+ // limits hold whatever time limits the database URL sets (see
8
+ // connection-time-limits.mjs).
9
+
10
+ import { ROLES_SQL, DATABASES_SQL, MAINTENANCE_DATABASE } from './cluster-changes.mjs';
11
+ import { timeLimitedClient } from './connection-time-limits.mjs';
12
+
13
+ /**
14
+ * How long each step may take. The server cancels a statement past
15
+ * `statementMs`; `queryMs`, a little longer, is the client giving up on a
16
+ * server that does not even answer that cancellation.
17
+ */
18
+ export const TIMEOUTS = { connectMs: 10000, statementMs: 15000, queryMs: 20000 };
19
+
20
+ // Everything that can be created in a non-system schema: relations (tables,
21
+ // views, sequences, indexes), functions and standalone types. Objects that
22
+ // belong to an extension don't count, since the server's template database
23
+ // can bring extensions along. Functions and types count because the
24
+ // migrations' CREATE OR REPLACE would replace them without an error.
25
+ export const EXISTING_OBJECTS_SQL = `
26
+ SELECT kind, name
27
+ FROM (
28
+ SELECT 'relation' AS kind, n.nspname || '.' || c.relname AS name, n.nspname,
29
+ 'pg_class'::regclass AS classid, c.oid AS objid
30
+ FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
31
+ UNION ALL
32
+ SELECT 'function', n.nspname || '.' || p.proname, n.nspname,
33
+ 'pg_proc'::regclass, p.oid
34
+ FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
35
+ UNION ALL
36
+ SELECT 'type', n.nspname || '.' || t.typname, n.nspname,
37
+ 'pg_type'::regclass, t.oid
38
+ FROM pg_type t JOIN pg_namespace n ON n.oid = t.typnamespace
39
+ WHERE t.typrelid = 0 AND t.typcategory <> 'A'
40
+ ) objects
41
+ WHERE nspname NOT IN ('pg_catalog', 'information_schema')
42
+ AND nspname !~ '^pg_(toast|temp)'
43
+ AND NOT EXISTS (
44
+ SELECT 1 FROM pg_depend d
45
+ WHERE d.classid = objects.classid AND d.objid = objects.objid AND d.deptype = 'e'
46
+ )
47
+ ORDER BY kind, name
48
+ LIMIT 5
49
+ `;
50
+
51
+ export function connect(connectionString, timeouts = TIMEOUTS, target = {}) {
52
+ return timeLimitedClient(connectionString, timeouts, target);
53
+ }
54
+
55
+ // `end()` drops the socket when a query is still active, so a connection whose
56
+ // query timed out closes instead of waiting for a server that is not answering.
57
+ async function withClient(connectionString, timeouts, work, target = {}) {
58
+ const client = connect(connectionString, timeouts, target);
59
+ await client.connect();
60
+ try {
61
+ return await work(client);
62
+ } finally {
63
+ await client.end();
64
+ }
65
+ }
66
+
67
+ /** What the target database holds, and what the cluster around it shows. */
68
+ export function inspectTarget(connectionString, timeouts = TIMEOUTS) {
69
+ return withClient(connectionString, timeouts, async client => {
70
+ const [objects, roles, databases] = await Promise.all([
71
+ client.query(EXISTING_OBJECTS_SQL),
72
+ client.query(ROLES_SQL),
73
+ client.query(DATABASES_SQL),
74
+ ]);
75
+ return { existingObjects: objects.rows, roles: roles.rows, databases: databases.rows };
76
+ });
77
+ }
78
+
79
+ /**
80
+ * What the maintenance database holds. A hosted Postgres keeps `postgres` for
81
+ * connections that only need the server, and a project whose own schema lives
82
+ * there looks, from the outside, like a server with nothing on it.
83
+ *
84
+ * The connection goes to the server and user the database URL names, as pg
85
+ * reads them, with only the database changed. The target database is compared
86
+ * the way pg resolves it too, so a URL with no database whose user is
87
+ * `postgres` is already the maintenance database.
88
+ *
89
+ * A server that refuses the connection, or the query, or does not answer it in
90
+ * time, is reported as unreachable rather than as empty: not being able to look
91
+ * is what a managed cluster looks like, and reading it as "nothing there" is
92
+ * how a run ends up creating cluster-wide roles on a server it was never
93
+ * allowed to inspect.
94
+ */
95
+ export async function inspectMaintenanceDatabase(databaseUrl, timeouts = TIMEOUTS) {
96
+ if (connect(databaseUrl, timeouts).database === MAINTENANCE_DATABASE) return { objects: [] };
97
+ try {
98
+ const result = await withClient(
99
+ databaseUrl,
100
+ timeouts,
101
+ client => client.query(EXISTING_OBJECTS_SQL),
102
+ { database: MAINTENANCE_DATABASE }
103
+ );
104
+ return { objects: result.rows };
105
+ } catch (error) {
106
+ return { unreachable: true, reason: error.message };
107
+ }
108
+ }