studiocms 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/dist/cli/add/index.d.ts +2 -2
  3. package/dist/cli/add/index.js +4 -3
  4. package/dist/cli/add/npm-utils.d.ts +6 -6
  5. package/dist/cli/add/tryToInstallPlugins.d.ts +1 -1
  6. package/dist/cli/add/tryToInstallPlugins.js +6 -5
  7. package/dist/cli/add/updateStudioCMSConfig.d.ts +1 -1
  8. package/dist/cli/add/updateStudioCMSConfig.js +3 -4
  9. package/dist/cli/add/validatePlugins.d.ts +1 -2
  10. package/dist/cli/add/validatePlugins.js +15 -9
  11. package/dist/cli/crypto/genJWT/index.d.ts +1 -1
  12. package/dist/cli/crypto/genJWT/index.js +8 -9
  13. package/dist/cli/crypto/index.d.ts +1 -1
  14. package/dist/cli/init/steps/env.js +14 -4
  15. package/dist/cli/init/steps/next.d.ts +1 -1
  16. package/dist/cli/init/steps/next.js +6 -5
  17. package/dist/cli/migrator/index.d.ts +1 -1
  18. package/dist/cli/migrator/index.js +2 -2
  19. package/dist/cli/users/index.d.ts +1 -1
  20. package/dist/cli/users/shared.js +2 -2
  21. package/dist/cli/users/steps/createUsers.js +7 -7
  22. package/dist/cli/users/steps/modifyUsers.js +2 -2
  23. package/dist/cli/users/steps/next.d.ts +1 -1
  24. package/dist/cli/utils/checkRequiredEnvVars.js +2 -2
  25. package/dist/cli/utils/context.d.ts +2 -4
  26. package/dist/cli/utils/context.js +1 -3
  27. package/dist/cli/utils/getCliDbClient.d.ts +1 -1
  28. package/dist/cli/utils/intro.d.ts +1 -1
  29. package/dist/cli/utils/loadConfig.d.ts +54 -49
  30. package/dist/cli/utils/loadConfig.js +5 -8
  31. package/dist/cli/utils/logger.js +3 -3
  32. package/dist/cli/utils/user-utils.d.ts +1 -1
  33. package/dist/cli/utils/user-utils.js +4 -3
  34. package/dist/client/apiClient.d.ts +4923 -0
  35. package/dist/client/apiClient.js +72 -0
  36. package/dist/config.d.ts +1734 -1
  37. package/dist/consts.d.ts +5 -5
  38. package/dist/consts.js +3 -2
  39. package/dist/db/plugins.d.ts +1 -1
  40. package/dist/db/plugins.js +5 -8
  41. package/dist/handlers/frontend/routes.d.ts +4 -18
  42. package/dist/handlers/frontend/routes.js +13 -152
  43. package/dist/handlers/frontend/types.d.ts +1 -1
  44. package/dist/handlers/frontend/utils.js +0 -18
  45. package/dist/handlers/pluginHandler.d.ts +34 -257
  46. package/dist/handlers/pluginHandler.js +92 -46
  47. package/dist/handlers/routeHandler.js +32 -11
  48. package/dist/handlers/setupDbStudio.d.ts +3 -1
  49. package/dist/handlers/setupDbStudio.js +19 -10
  50. package/dist/handlers/storage-manager/core/effectify-astro-context.d.ts +25 -0
  51. package/dist/handlers/storage-manager/core/effectify-astro-context.js +78 -0
  52. package/dist/handlers/storage-manager/no-op.d.ts +2 -2
  53. package/dist/handlers/storage-manager/no-op.js +2 -3
  54. package/dist/index.d.ts +0 -1
  55. package/dist/index.js +10 -20
  56. package/dist/integrations/robots/index.d.ts +2 -2
  57. package/dist/integrations/robots/index.js +1 -3
  58. package/dist/integrations/robots/schema.d.ts +102 -273
  59. package/dist/integrations/robots/schema.js +220 -209
  60. package/dist/plugins/analytics/assets/schemas.d.ts +14 -9
  61. package/dist/plugins/analytics/assets/schemas.js +25 -17
  62. package/dist/plugins/analytics/db-client.d.ts +1 -1
  63. package/dist/plugins/analytics/index.d.ts +823 -3
  64. package/dist/plugins/analytics/index.js +4 -5
  65. package/dist/plugins/analytics/schemas.d.ts +54 -62
  66. package/dist/plugins/analytics/schemas.js +64 -13
  67. package/dist/plugins/analytics/table.d.ts +1 -1
  68. package/dist/plugins.d.ts +0 -1
  69. package/dist/schemas/config/api.d.ts +17 -0
  70. package/dist/schemas/config/api.js +14 -0
  71. package/dist/schemas/config/auth.d.ts +55 -59
  72. package/dist/schemas/config/auth.js +34 -11
  73. package/dist/schemas/config/dashboard.d.ts +43 -79
  74. package/dist/schemas/config/dashboard.js +43 -12
  75. package/dist/schemas/config/db.d.ts +15 -17
  76. package/dist/schemas/config/db.js +13 -5
  77. package/dist/schemas/config/developer.d.ts +33 -45
  78. package/dist/schemas/config/developer.js +22 -5
  79. package/dist/schemas/config/index.d.ts +398 -521
  80. package/dist/schemas/config/index.js +115 -57
  81. package/dist/schemas/config/sdk.d.ts +50 -196
  82. package/dist/schemas/config/sdk.js +61 -73
  83. package/dist/schemas/custom.d.ts +40 -0
  84. package/dist/schemas/custom.js +41 -0
  85. package/dist/schemas/external-schemas.d.ts +171 -0
  86. package/dist/schemas/external-schemas.js +179 -0
  87. package/dist/schemas/index.d.ts +2 -0
  88. package/dist/schemas/index.js +2 -0
  89. package/dist/schemas/plugins/i18n.d.ts +59 -39
  90. package/dist/schemas/plugins/i18n.js +42 -5
  91. package/dist/schemas/plugins/index.d.ts +7126 -10296
  92. package/dist/schemas/plugins/index.js +260 -276
  93. package/dist/schemas/plugins/shared.d.ts +1293 -3718
  94. package/dist/schemas/plugins/shared.js +320 -329
  95. package/dist/test-utils.d.ts +15 -4
  96. package/dist/test-utils.js +27 -11
  97. package/dist/toolbar/db-viewer/db-shared-types.d.ts +6 -6
  98. package/dist/toolbar/db-viewer/studio/connection.d.ts +8 -4
  99. package/dist/toolbar/db-viewer/studio/connection.js +2 -28
  100. package/dist/toolbar/db-viewer/studio/env/libsql.d.ts +7 -0
  101. package/dist/toolbar/db-viewer/studio/env/libsql.js +17 -0
  102. package/dist/toolbar/db-viewer/studio/env/mysql.d.ts +7 -0
  103. package/dist/toolbar/db-viewer/studio/env/mysql.js +23 -0
  104. package/dist/toolbar/db-viewer/studio/env/postgres.d.ts +7 -0
  105. package/dist/toolbar/db-viewer/studio/env/postgres.js +23 -0
  106. package/dist/toolbar/db-viewer/studio/index.js +20 -56
  107. package/dist/toolbar/db-viewer/studio/type.d.ts +1 -2
  108. package/dist/toolbar/db-viewer/studio/virtual-connection/libsql.d.ts +3 -0
  109. package/dist/toolbar/db-viewer/studio/virtual-connection/libsql.js +24 -0
  110. package/dist/toolbar/db-viewer/studio/virtual-connection/mysql.d.ts +3 -0
  111. package/dist/toolbar/db-viewer/studio/virtual-connection/mysql.js +9 -0
  112. package/dist/toolbar/db-viewer/studio/virtual-connection/postgres.d.ts +3 -0
  113. package/dist/toolbar/db-viewer/studio/virtual-connection/postgres.js +9 -0
  114. package/dist/toolbar/db-viewer/viewer.js +20 -21
  115. package/dist/types.d.ts +30 -0
  116. package/dist/utils/effects/smtp.d.ts +1 -1
  117. package/dist/utils/lang-helper.d.ts +10 -2
  118. package/dist/virtual.d.ts +35 -28
  119. package/dist/virtuals/auth/core.d.ts +5 -5
  120. package/dist/virtuals/auth/verify-email.d.ts +6 -6
  121. package/dist/virtuals/components/Generator.astro +2 -2
  122. package/dist/virtuals/components/Renderer.astro +9 -1
  123. package/dist/virtuals/components/renderFn.d.ts +3 -1
  124. package/dist/virtuals/components/renderFn.js +18 -0
  125. package/dist/virtuals/lib/headDefaults.d.ts +4 -2
  126. package/dist/virtuals/lib/headDefaults.js +0 -2
  127. package/dist/virtuals/lib/routeMap.d.ts +0 -12
  128. package/dist/virtuals/lib/routeMap.js +2 -14
  129. package/dist/virtuals/mailer/index.d.ts +3 -3
  130. package/dist/virtuals/notifier/index.d.ts +5 -5
  131. package/dist/virtuals/plugins/dashboard-pages.d.ts +2 -64
  132. package/dist/virtuals/scripts/StorageFileBrowser.d.ts +1 -172
  133. package/dist/virtuals/scripts/StorageFileBrowser.js +216 -119
  134. package/dist/virtuals/template-engine/index.d.ts +4 -4
  135. package/frontend/components/dashboard/configuration/ConfigForm.astro +218 -110
  136. package/frontend/components/dashboard/content-mgmt/ContentSearch.astro +21 -22
  137. package/frontend/components/dashboard/content-mgmt/CreateFolder.astro +66 -54
  138. package/frontend/components/dashboard/content-mgmt/CreatePage.astro +58 -104
  139. package/frontend/components/dashboard/content-mgmt/EditFolder.astro +65 -67
  140. package/frontend/components/dashboard/content-mgmt/EditPage.astro +86 -134
  141. package/frontend/components/dashboard/content-mgmt/InnerSidebarElement.astro +0 -1
  142. package/frontend/components/dashboard/content-mgmt/PageHeader.astro +33 -52
  143. package/frontend/components/dashboard/content-mgmt/PageTypeHandler.astro +2 -2
  144. package/frontend/components/dashboard/profile/APITokens.astro +219 -158
  145. package/frontend/components/dashboard/profile/BasicInfo.astro +165 -106
  146. package/frontend/components/dashboard/profile/Notifications.astro +27 -18
  147. package/frontend/components/dashboard/profile/UpdatePassword.astro +134 -94
  148. package/frontend/components/dashboard/sidebar/VersionCheck.astro +31 -16
  149. package/frontend/components/dashboard/sidebar/VersionCheckChangelog.astro +18 -11
  150. package/frontend/components/dashboard/sidebar-modals/VersionModal.astro +2 -2
  151. package/frontend/components/dashboard/smtp-config/TemplateEditor.astro +14 -14
  152. package/frontend/components/dashboard/taxonomy/InnerSidebarElement.astro +0 -1
  153. package/frontend/components/dashboard/taxonomy/MetaContainer.astro +0 -2
  154. package/frontend/components/dashboard/taxonomy/PageHeader.astro +16 -24
  155. package/frontend/components/dashboard/taxonomy/TaxonomySearch.astro +23 -27
  156. package/frontend/components/dashboard/user-mgmt/InnerSidebarElement.astro +111 -104
  157. package/frontend/components/dashboard/user-mgmt/UserListItem.astro +9 -22
  158. package/frontend/components/dashboard/user-mgmt/UserListItems.astro +18 -0
  159. package/frontend/components/first-time-setup/snippets/{opt2-studiocms.config.diff → studiocms.config.diff} +1 -0
  160. package/frontend/components/shared/Code.astro +1 -4
  161. package/frontend/components/shared/DynamicSettingsRenderer.astro +1 -1
  162. package/frontend/components/shared/SSRUser.astro +2 -4
  163. package/frontend/components/shared/foldertree/FolderTreeNode.astro +0 -6
  164. package/frontend/components/shared/storage-manager/StorageCopyOutput.astro +0 -1
  165. package/frontend/components/shared/taxonomy/TaxonomyTreeNode.astro +0 -6
  166. package/frontend/layouts/DashboardLayout.astro +1 -10
  167. package/frontend/layouts/TaxonomyLayout.astro +0 -1
  168. package/frontend/middleware/index.ts +102 -61
  169. package/frontend/pages/404.astro +5 -9
  170. package/frontend/pages/[dashboard]/[...pluginPage].astro +10 -1
  171. package/frontend/pages/[dashboard]/configuration.astro +10 -1
  172. package/frontend/pages/[dashboard]/content-management/createfolder.astro +10 -1
  173. package/frontend/pages/[dashboard]/content-management/createpage.astro +10 -1
  174. package/frontend/pages/[dashboard]/content-management/diff.astro +39 -14
  175. package/frontend/pages/[dashboard]/content-management/editfolder.astro +10 -1
  176. package/frontend/pages/[dashboard]/content-management/editpage.astro +10 -1
  177. package/frontend/pages/[dashboard]/content-management/index.astro +10 -1
  178. package/frontend/pages/[dashboard]/index.astro +10 -1
  179. package/frontend/pages/[dashboard]/login.astro +86 -25
  180. package/frontend/pages/[dashboard]/password-reset.astro +22 -16
  181. package/frontend/pages/[dashboard]/plugins/[plugin].astro +10 -1
  182. package/frontend/pages/[dashboard]/profile.astro +10 -1
  183. package/frontend/pages/[dashboard]/signup.astro +153 -52
  184. package/frontend/pages/[dashboard]/smtp-configuration.astro +77 -75
  185. package/frontend/pages/[dashboard]/system-management.astro +10 -1
  186. package/frontend/pages/[dashboard]/taxonomy/categories.astro +30 -41
  187. package/frontend/pages/[dashboard]/taxonomy/index.astro +10 -0
  188. package/frontend/pages/[dashboard]/taxonomy/tags.astro +33 -43
  189. package/frontend/pages/[dashboard]/unverified-email.astro +29 -21
  190. package/frontend/pages/[dashboard]/user-management/edit.astro +170 -90
  191. package/frontend/pages/[dashboard]/user-management/index.astro +10 -1
  192. package/frontend/pages/studiocms_api/[...all].ts +106 -0
  193. package/frontend/pages/studiocms_api/_handlers/_utils/auth.ts +26 -0
  194. package/frontend/pages/studiocms_api/_handlers/_utils/changelog.ts +147 -0
  195. package/frontend/pages/studiocms_api/_handlers/_utils/db-studio-driver.ts +46 -0
  196. package/frontend/pages/studiocms_api/_handlers/_utils/parseLogLevel.ts +27 -0
  197. package/frontend/pages/studiocms_api/_handlers/auth/auth.ts +459 -0
  198. package/frontend/pages/studiocms_api/_handlers/auth/index.ts +17 -0
  199. package/frontend/pages/studiocms_api/_handlers/auth/oauth.ts +91 -0
  200. package/frontend/pages/studiocms_api/_handlers/dashboard/_shared.ts +57 -0
  201. package/frontend/pages/studiocms_api/_handlers/dashboard/apiTokens.ts +134 -0
  202. package/frontend/pages/studiocms_api/_handlers/dashboard/config.ts +64 -0
  203. package/frontend/pages/studiocms_api/_handlers/dashboard/content.ts +741 -0
  204. package/frontend/pages/studiocms_api/_handlers/dashboard/create.ts +480 -0
  205. package/frontend/pages/studiocms_api/_handlers/dashboard/emailNotifications.ts +49 -0
  206. package/frontend/pages/studiocms_api/_handlers/dashboard/index.ts +45 -0
  207. package/frontend/pages/studiocms_api/_handlers/dashboard/mailer.ts +136 -0
  208. package/frontend/pages/studiocms_api/_handlers/dashboard/plugins.ts +80 -0
  209. package/frontend/pages/studiocms_api/_handlers/dashboard/profile.ts +275 -0
  210. package/frontend/pages/studiocms_api/_handlers/dashboard/resetPassword.ts +140 -0
  211. package/frontend/pages/studiocms_api/_handlers/dashboard/search.ts +63 -0
  212. package/frontend/pages/studiocms_api/_handlers/dashboard/taxonomy.ts +285 -0
  213. package/frontend/pages/studiocms_api/_handlers/dashboard/templates.ts +75 -0
  214. package/frontend/pages/studiocms_api/_handlers/dashboard/users.ts +312 -0
  215. package/frontend/pages/studiocms_api/_handlers/dashboard/verifyEndpoints.ts +307 -0
  216. package/frontend/pages/studiocms_api/_handlers/integration/dbStudio.ts +98 -0
  217. package/frontend/pages/studiocms_api/_handlers/integration/index.ts +17 -0
  218. package/frontend/pages/studiocms_api/_handlers/integration/storageManager.ts +107 -0
  219. package/frontend/pages/studiocms_api/_handlers/rest-api/index.ts +8 -0
  220. package/frontend/pages/studiocms_api/_handlers/rest-api/v1/_shared.ts +41 -0
  221. package/frontend/pages/studiocms_api/_handlers/rest-api/v1/index.ts +17 -0
  222. package/frontend/pages/studiocms_api/_handlers/rest-api/v1/public.ts +195 -0
  223. package/frontend/pages/studiocms_api/_handlers/rest-api/v1/secure.ts +1726 -0
  224. package/frontend/pages/studiocms_api/_handlers/sdk.ts +129 -0
  225. package/frontend/pages/studiocms_api/_middleware/astroLocals.ts +36 -0
  226. package/frontend/pages/studiocms_api/_middleware/restApi.ts +56 -0
  227. package/frontend/pages/studiocms_api/integrations/[...all].ts +8 -0
  228. package/frontend/scripts/formdata.ts +219 -0
  229. package/frontend/setup-pages/3-done.astro +4 -20
  230. package/frontend/setup-pages/studiocms_api/dashboard/step-2.ts +3 -6
  231. package/frontend/styles/dashboard-base.css +0 -1
  232. package/frontend/web-vitals/endpoint.ts +2 -1
  233. package/package.json +35 -31
  234. package/dist/global.d.ts +0 -9
  235. package/frontend/components/dashboard/LoginChecker.astro +0 -68
  236. package/frontend/components/dashboard/user-mgmt/RankCheck.astro +0 -57
  237. package/frontend/components/first-time-setup/snippets/opt1-astro.config.diff +0 -14
  238. package/frontend/components/first-time-setup/snippets/opt2-astro.config.diff +0 -9
  239. package/frontend/middleware/_authmap.ts +0 -63
  240. package/frontend/pages/studiocms_api/auth/[path].ts +0 -390
  241. package/frontend/pages/studiocms_api/auth/[provider]/[...id].ts +0 -64
  242. package/frontend/pages/studiocms_api/auth/[provider]/_effects/index.ts +0 -101
  243. package/frontend/pages/studiocms_api/auth/_shared.ts +0 -52
  244. package/frontend/pages/studiocms_api/dashboard/api-tokens.ts +0 -115
  245. package/frontend/pages/studiocms_api/dashboard/config.ts +0 -74
  246. package/frontend/pages/studiocms_api/dashboard/content/diff.ts +0 -73
  247. package/frontend/pages/studiocms_api/dashboard/content/folder.ts +0 -220
  248. package/frontend/pages/studiocms_api/dashboard/content/page.ts +0 -359
  249. package/frontend/pages/studiocms_api/dashboard/create-reset-link.ts +0 -77
  250. package/frontend/pages/studiocms_api/dashboard/create-user-invite.ts +0 -231
  251. package/frontend/pages/studiocms_api/dashboard/create-user.ts +0 -186
  252. package/frontend/pages/studiocms_api/dashboard/email-notification-settings-site.ts +0 -74
  253. package/frontend/pages/studiocms_api/dashboard/mailer/check-email.ts +0 -75
  254. package/frontend/pages/studiocms_api/dashboard/mailer/config.ts +0 -136
  255. package/frontend/pages/studiocms_api/dashboard/plugins/[plugin].ts +0 -80
  256. package/frontend/pages/studiocms_api/dashboard/profile.ts +0 -245
  257. package/frontend/pages/studiocms_api/dashboard/resend-verify-email.ts +0 -77
  258. package/frontend/pages/studiocms_api/dashboard/reset-password.ts +0 -124
  259. package/frontend/pages/studiocms_api/dashboard/search-list.ts +0 -59
  260. package/frontend/pages/studiocms_api/dashboard/taxonomy-search.ts +0 -47
  261. package/frontend/pages/studiocms_api/dashboard/taxonomy.ts +0 -230
  262. package/frontend/pages/studiocms_api/dashboard/templates.ts +0 -74
  263. package/frontend/pages/studiocms_api/dashboard/update-user-notifications.ts +0 -86
  264. package/frontend/pages/studiocms_api/dashboard/users.ts +0 -236
  265. package/frontend/pages/studiocms_api/dashboard/verify-email.ts +0 -83
  266. package/frontend/pages/studiocms_api/dashboard/verify-session.ts +0 -187
  267. package/frontend/pages/studiocms_api/integrations/[type]/[...id].ts +0 -15
  268. package/frontend/pages/studiocms_api/integrations/[type]/_routes/db-studio.ts +0 -173
  269. package/frontend/pages/studiocms_api/integrations/[type]/_routes/storage.ts +0 -88
  270. package/frontend/pages/studiocms_api/partials/editor.astro +0 -74
  271. package/frontend/pages/studiocms_api/partials/render.astro +0 -39
  272. package/frontend/pages/studiocms_api/partials/user-list-items.astro +0 -43
  273. package/frontend/pages/studiocms_api/rest/utils/auth-token.ts +0 -59
  274. package/frontend/pages/studiocms_api/rest/v1/[type]/[...id].ts +0 -23
  275. package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/categories.ts +0 -267
  276. package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/folders.ts +0 -283
  277. package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/pages.ts +0 -505
  278. package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/settings.ts +0 -100
  279. package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/tags.ts +0 -229
  280. package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/users.ts +0 -553
  281. package/frontend/pages/studiocms_api/rest/v1/public/[type]/[...id].ts +0 -19
  282. package/frontend/pages/studiocms_api/rest/v1/public/[type]/_routes/categories.ts +0 -74
  283. package/frontend/pages/studiocms_api/rest/v1/public/[type]/_routes/folders.ts +0 -85
  284. package/frontend/pages/studiocms_api/rest/v1/public/[type]/_routes/pages.ts +0 -103
  285. package/frontend/pages/studiocms_api/rest/v1/public/[type]/_routes/tags.ts +0 -67
  286. package/frontend/pages/studiocms_api/sdk/[...path].ts +0 -97
  287. package/frontend/pages/studiocms_api/sdk/utils/changelog.ts +0 -119
  288. package/frontend/scripts/auth/formListener.ts +0 -81
  289. package/frontend/scripts/formdata-utils.ts +0 -116
  290. package/frontend/utils/build-partial-schema.ts +0 -46
  291. package/frontend/utils/errors.ts +0 -6
  292. package/frontend/utils/param-extractor.ts +0 -83
  293. package/frontend/utils/rest-router.ts +0 -444
@@ -1,4 +1,5 @@
1
1
  ---
2
+ import { User } from 'studiocms:auth/lib';
2
3
  import { FormattedDate } from 'studiocms:components';
3
4
  import { useTranslations } from 'studiocms:i18n';
4
5
  import { SDKCore } from 'studiocms:sdk';
@@ -11,9 +12,9 @@ import { Input } from 'studiocms:ui/components/input';
11
12
  import { Modal } from 'studiocms:ui/components/modal';
12
13
  import { Select } from 'studiocms:ui/components/select';
13
14
  import { Effect, genLogger, runEffect } from '@withstudiocms/effect';
15
+ import { setDataContext } from '@withstudiocms/effect/astro/data-middleware';
14
16
  import PageHeader from '../../../components/dashboard/PageHeader.astro';
15
17
  import InnerSidebarElement from '../../../components/dashboard/user-mgmt/InnerSidebarElement.astro';
16
- import RankCheck from '../../../components/dashboard/user-mgmt/RankCheck.astro';
17
18
  import SocialSignin from '../../../components/dashboard/user-mgmt/SocialSignin.astro';
18
19
  import { providerData, showOAuth } from '../../../components/shared/oAuthButtonProviders.js';
19
20
  import Layout from '../../../layouts/DashboardLayout.astro';
@@ -62,20 +63,35 @@ const disableDelete = user?.permissionsData?.rank === 'owner' || user?.id === us
62
63
  if (isOwner) allowedRanks.unshift({ label: 'Owner', value: 'owner' });
63
64
 
64
65
  if (isAdmin) allowedRanks.unshift({ label: 'Administrator', value: 'admin' });
66
+
67
+ const isAuthorized = await Effect.runPromise(
68
+ Effect.gen(function* () {
69
+ const { isUserAllowed } = yield* User;
70
+ return yield* isUserAllowed(userSession, user?.permissionsData?.rank ?? 'unknown');
71
+ })
72
+ );
73
+
74
+ if (!isAuthorized) {
75
+ return Astro.redirect(Astro.locals.StudioCMS.routeMap.mainLinks.userManagement);
76
+ }
77
+
78
+ setDataContext(Astro, {
79
+ key: 'x-required-role',
80
+ value: 'admin',
81
+ });
82
+ setDataContext(Astro, {
83
+ key: 'x-redirect-url',
84
+ value: Astro.locals.StudioCMS.routeMap.mainLinks.dashboardIndex,
85
+ });
65
86
  ---
66
87
  <Layout
67
88
  title={t('title')}
68
89
  description={t('description')}
69
- requiredPermission='admin'
70
90
  sidebar='double'
71
91
  {lang}
72
92
  {config}
73
93
  currentUser={userSession}
74
94
  >
75
- {/*
76
- Check if the user has the required permission to manage the user's rank level
77
- */}
78
- <RankCheck requiredPermission={user?.permissionsData?.rank} />
79
95
 
80
96
  <div slot="double-sidebar" class="inner-sidebar-container">
81
97
  <div class="sidebar-user-links-container">
@@ -325,27 +341,22 @@ if (isAdmin) allowedRanks.unshift({ label: 'Administrator', value: 'admin' });
325
341
  <script>
326
342
  import { toast } from 'studiocms:ui/components/toaster/client';
327
343
  import { ModalHelper } from 'studiocms:ui/components/modal/client';
344
+ import { dashboardClient, dashboardSharedCatchTags } from 'studiocms:client/apiClients';
345
+ import * as Effect from 'effect/Effect';
346
+ import { availablePermissionRanks, type AvailablePermissionRanks } from '@withstudiocms/auth-kit/types';
328
347
 
329
348
  const resetLinkModal = new ModalHelper('password-reset-link-modal');
330
349
 
331
350
  const deleteButtons = document.querySelectorAll('[data-token]') as NodeListOf<HTMLButtonElement>;
332
351
 
333
- const tokenAPILinks = document.getElementById('token-api-links') as HTMLDivElement;
334
-
335
- const tokenAPI = tokenAPILinks.dataset.token_api!;
336
-
337
352
  const editUserForm = document.getElementById('edit-user-form') as HTMLFormElement;
338
353
 
339
- const deleteUserAction = (document.getElementById('delete-user-modal-trigger') as HTMLButtonElement).dataset.action;
340
-
341
354
  const userDeleteModal = new ModalHelper('delete-user-modal', 'delete-user-modal-trigger');
342
355
 
343
356
  const passwordResetLinkTrigger = document.getElementById('password-reset-link-trigger') as HTMLButtonElement;
344
357
  const resetLinkPlaceholder = document.getElementById('reset-link-placeholder') as HTMLElement;
345
358
 
346
- const resetLinkAPI = (document.getElementById('reset-link-selector') as HTMLDivElement).dataset.link;
347
359
  const userId = (document.getElementById('reset-link-selector') as HTMLDivElement).dataset.userid;
348
- const dashboardIndex = (document.getElementById('reset-link-selector') as HTMLDivElement).dataset.dashboard;
349
360
 
350
361
  const passwordResetUrl = (document.getElementById('reset-link-selector') as HTMLDivElement).dataset.reseturl;
351
362
 
@@ -360,27 +371,44 @@ if (isAdmin) allowedRanks.unshift({ label: 'Administrator', value: 'admin' });
360
371
  passwordResetLinkTrigger.addEventListener('click', async (e) => {
361
372
  e.preventDefault();
362
373
 
363
- const apiRes = await fetch(resetLinkAPI!, {
364
- method: 'POST',
365
- headers: {
366
- 'Content-Type': 'application/json',
367
- },
368
- body: JSON.stringify({ userId: userId })
369
- });
370
-
371
- const token = await apiRes.json();
372
-
373
- if (!apiRes.ok) {
374
- console.error('Failed to create reset link');
374
+ if (!userId) {
375
375
  toast({
376
376
  title: 'Error',
377
- description: token.error,
377
+ description: 'User ID is missing. Cannot generate password reset link.',
378
378
  type: 'danger'
379
379
  })
380
380
  return;
381
381
  }
382
382
 
383
- resetLinkPlaceholder.innerText = generateResetLink(token);
383
+ const response = await dashboardClient.pipe(
384
+ Effect.flatMap((client) =>
385
+ client.create.createPasswordResetLink({
386
+ payload: {
387
+ userId
388
+ }
389
+ })
390
+ ),
391
+ Effect.catchTags(dashboardSharedCatchTags),
392
+ Effect.runPromise
393
+ )
394
+
395
+ if ('error' in response) {
396
+ toast({
397
+ title: 'Error',
398
+ description: response.error,
399
+ type: 'danger',
400
+ });
401
+ return;
402
+ } else if (!response) {
403
+ toast({
404
+ title: 'Error',
405
+ description: 'Failed to generate password reset link.',
406
+ type: 'danger',
407
+ });
408
+ return;
409
+ }
410
+
411
+ resetLinkPlaceholder.innerText = generateResetLink(response);
384
412
 
385
413
  resetLinkModal.show();
386
414
  })
@@ -391,36 +419,55 @@ if (isAdmin) allowedRanks.unshift({ label: 'Administrator', value: 'admin' });
391
419
  return
392
420
  };
393
421
 
394
- const data = {
395
- userId: formData.get('user-id')?.toString(),
396
- username: formData.get('user-username')?.toString(),
397
- usernameConfirm: formData.get('confirm-user-username')?.toString()
398
- }
422
+ const userId = formData.get('user-id')?.toString();
423
+ const username = formData.get('user-username')?.toString();
424
+ const usernameConfirm = formData.get('confirm-user-username')?.toString();
399
425
 
400
- const response = await fetch(deleteUserAction!, {
401
- method: 'DELETE',
402
- headers: {
403
- 'Content-Type': 'application/json',
404
- },
405
- body: JSON.stringify(data)
406
- })
407
-
408
- const res = await response.json();
426
+ if (!userId || !username || !usernameConfirm) {
427
+ toast({
428
+ title: 'Error',
429
+ description: 'Missing necessary data to delete user.',
430
+ type: 'danger'
431
+ })
432
+ return;
433
+ }
409
434
 
410
- if (response.status !== 200) {
435
+ if (username !== usernameConfirm) {
411
436
  toast({
412
437
  title: 'Error',
413
- description: res.error,
438
+ description: 'Username confirmation does not match.',
414
439
  type: 'danger'
415
440
  })
441
+ return;
416
442
  }
417
443
 
418
- if (response.status === 200) {
444
+ const response = await dashboardClient.pipe(
445
+ Effect.flatMap((client) =>
446
+ client.users.deleteUser({
447
+ payload: {
448
+ userId,
449
+ username,
450
+ usernameConfirm
451
+ }
452
+ })
453
+ ),
454
+ Effect.catchTags(dashboardSharedCatchTags),
455
+ Effect.runPromise
456
+ );
457
+
458
+ if ('error' in response) {
459
+ toast({
460
+ title: 'Error',
461
+ description: response.error,
462
+ type: 'danger',
463
+ });
464
+ return;
465
+ } else {
419
466
  toast({
420
467
  title: 'Success',
421
- description: res.message,
422
- type: 'success'
423
- })
468
+ description: response.message || 'User deleted successfully.',
469
+ type: 'success',
470
+ });
424
471
  }
425
472
  })
426
473
 
@@ -429,78 +476,111 @@ if (isAdmin) allowedRanks.unshift({ label: 'Administrator', value: 'admin' });
429
476
 
430
477
  const formData = new FormData(editUserForm);
431
478
 
432
- const data = {
433
- id: formData.get('user-id')?.toString(),
434
- rank: formData.get('rank')?.toString(),
435
- emailVerified: formData.get('email-verified') === 'true'
436
- }
479
+ const id = formData.get('user-id')?.toString();
480
+ let rank = formData.get('rank')?.toString();
481
+ const emailVerified = formData.get('email-verified')?.toString() === 'true';
437
482
 
438
- const response = await fetch(editUserForm.action, {
439
- method: 'POST',
440
- headers: {
441
- 'Content-Type': 'application/json',
442
- },
443
- body: JSON.stringify(data)
444
- })
483
+ if (!id || !rank || emailVerified === undefined) {
484
+ toast({
485
+ title: 'Error',
486
+ description: 'Missing necessary data to update user.',
487
+ type: 'danger'
488
+ })
489
+ return;
490
+ }
445
491
 
446
- const res = await response.json();
492
+ function isAvailableRank(rank: string): rank is AvailablePermissionRanks {
493
+ return availablePermissionRanks.includes(rank as AvailablePermissionRanks);
494
+ }
447
495
 
448
- if (response.status !== 200) {
496
+ if (!isAvailableRank(rank)) {
449
497
  toast({
450
498
  title: 'Error',
451
- description: res.error,
499
+ description: 'Invalid rank value.',
452
500
  type: 'danger'
453
501
  })
502
+ return;
454
503
  }
455
504
 
456
- if (response.status === 200) {
505
+ const response = await dashboardClient.pipe(
506
+ Effect.flatMap((client) =>
507
+ client.users.updateUser({
508
+ payload: {
509
+ id,
510
+ emailVerified,
511
+ rank
512
+ }
513
+ })
514
+ ),
515
+ Effect.catchTags(dashboardSharedCatchTags),
516
+ Effect.runPromise
517
+ );
518
+
519
+ if ('error' in response) {
520
+ toast({
521
+ title: 'Error',
522
+ description: response.error,
523
+ type: 'danger',
524
+ });
525
+ return;
526
+ } else {
457
527
  toast({
458
528
  title: 'Success',
459
- description: res.message,
460
- type: 'success'
461
- })
529
+ description: response.message || 'User updated successfully.',
530
+ type: 'success',
531
+ });
462
532
  }
463
533
  })
464
534
 
465
535
  deleteButtons.forEach((button) => {
466
536
  button.addEventListener('click', async (event) => {
467
537
  event.preventDefault();
538
+
468
539
  const tokenID = button.getAttribute('data-token');
469
540
  const userID = button.getAttribute('data-user');
470
-
471
- const response = await fetch(tokenAPI, {
472
- method: 'DELETE',
473
- headers: {
474
- 'Content-Type': 'application/json'
475
- },
476
- body: JSON.stringify({
477
- tokenID,
478
- userID
479
- })
480
- });
481
-
482
- const res = await response.json();
483
-
484
- if (!response.ok) {
541
+
542
+ if (!tokenID || !userID) {
485
543
  toast({
486
544
  title: 'Error',
487
- description: res.error,
545
+ description: 'Missing necessary data to revoke API token.',
488
546
  type: 'danger',
489
547
  duration: 5000
490
548
  })
491
549
  return;
492
550
  }
493
551
 
494
- toast({
552
+ const response = await dashboardClient.pipe(
553
+ Effect.flatMap((client) =>
554
+ client.apiTokens.adminRevokeUserApiToken({
555
+ payload: {
556
+ tokenID,
557
+ userID
558
+ }
559
+ })
560
+ ),
561
+ Effect.catchTags(dashboardSharedCatchTags),
562
+ Effect.runPromise
563
+ );
564
+
565
+ if ('error' in response) {
566
+ toast({
567
+ title: 'Error',
568
+ description: response.error,
569
+ type: 'danger',
570
+ duration: 5000
571
+ })
572
+ return;
573
+ } else {
574
+ toast({
495
575
  title: 'Success',
496
- description: res.message,
576
+ description: response.message || 'API token revoked successfully.',
497
577
  type: 'success',
498
578
  duration: 5000
499
- })
500
-
501
- setTimeout(() => {
502
- window.location.reload();
503
- }, 1000);
579
+ })
580
+ setTimeout(() => {
581
+ window.location.reload();
582
+ }, 1000);
583
+ }
504
584
  });
505
585
  });
506
586
  </script>
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  import { useTranslations } from 'studiocms:i18n';
3
+ import { setDataContext } from '@withstudiocms/effect/astro/data-middleware';
3
4
  import PageHeader from '../../../components/dashboard/PageHeader.astro';
4
5
  import InnerSidebarElement from '../../../components/dashboard/user-mgmt/InnerSidebarElement.astro';
5
6
  import Layout from '../../../layouts/DashboardLayout.astro';
@@ -9,11 +10,19 @@ const { siteConfig: config, defaultLang: lang, security } = Astro.locals.StudioC
9
10
  const currentUser = security?.userSessionData ?? null;
10
11
 
11
12
  const t = useTranslations(lang, '@studiocms/dashboard:user-mngmt-index');
13
+
14
+ setDataContext(Astro, {
15
+ key: 'x-required-role',
16
+ value: 'admin',
17
+ });
18
+ setDataContext(Astro, {
19
+ key: 'x-redirect-url',
20
+ value: Astro.locals.StudioCMS.routeMap.mainLinks.dashboardIndex,
21
+ });
12
22
  ---
13
23
  <Layout
14
24
  title={t('title')}
15
25
  description={t('description')}
16
- requiredPermission='admin'
17
26
  sidebar='double'
18
27
  {lang}
19
28
  {config}
@@ -0,0 +1,106 @@
1
+ import config from 'studiocms:config';
2
+ import { HttpApiBuilder, HttpServerResponse } from '@effect/platform';
3
+ import type { Api } from '@effect/platform/HttpApi';
4
+ import {
5
+ StudioCMSAuthApi,
6
+ StudioCMSDashboardApiSpec,
7
+ StudioCMSIntegrationsApiSpec,
8
+ StudioCMSRestApiV1Spec,
9
+ StudioCMSSDKApiSpec,
10
+ } from '@withstudiocms/api-spec';
11
+ import type { APIRoute } from 'astro';
12
+ import { Layer } from 'effect';
13
+ import { HttpApiToAstroRoute } from 'effectify/astro/HttpApi';
14
+ import * as Scalar from 'effectify/scalar';
15
+ import { AuthAPILive } from './_handlers/auth/index.js';
16
+ import { DashboardAPILive } from './_handlers/dashboard/index.js';
17
+ import { IntegrationsAPILive } from './_handlers/integration/index.js';
18
+ import { RestAPILive } from './_handlers/rest-api/index.js';
19
+ import { SDKAPILive } from './_handlers/sdk.js';
20
+
21
+ /**
22
+ * Scalar layer for the StudioCMS API Documentation route, providing a custom header and linking to the documentation for all API specifications.
23
+ */
24
+ const DocsRouteLive = Scalar.layer({
25
+ title: 'StudioCMS API Documentation',
26
+ description:
27
+ 'The Documentation for the StudioCMS API, including all available endpoints and specifications.',
28
+ customHeader: {
29
+ title: {
30
+ text: 'StudioCMS API Documentation',
31
+ link: '/studiocms_api/docs',
32
+ },
33
+ nav: [
34
+ {
35
+ text: 'StudioCMS Website',
36
+ link: 'https://studiocms.dev',
37
+ },
38
+ {
39
+ text: 'GitHub Repository',
40
+ link: 'https://github.com/withstudiocms/studiocms',
41
+ },
42
+ {
43
+ text: 'StudioCMS Discord',
44
+ link: 'https://chat.studiocms.dev',
45
+ },
46
+ ],
47
+ },
48
+ path: '/studiocms_api/docs',
49
+ sources: [
50
+ {
51
+ title: 'Auth API',
52
+ httpApi: StudioCMSAuthApi,
53
+ },
54
+ {
55
+ title: 'Dashboard API',
56
+ httpApi: StudioCMSDashboardApiSpec,
57
+ },
58
+ {
59
+ title: 'Integrations API',
60
+ httpApi: StudioCMSIntegrationsApiSpec,
61
+ },
62
+ {
63
+ title: 'REST API v1',
64
+ httpApi: StudioCMSRestApiV1Spec,
65
+ },
66
+ {
67
+ title: 'SDK API',
68
+ httpApi: StudioCMSSDKApiSpec,
69
+ },
70
+ ],
71
+ });
72
+
73
+ /**
74
+ * Catch-All Route Layer - Provides a catch-all route that redirects any unmatched requests to a 404 page.
75
+ *
76
+ * This is needed to ensure that any requests that are passed to the Effect API handlers return an Astro 404 page instead of the Effect 404 response.
77
+ */
78
+ export const CatchAllGroup = HttpApiBuilder.Router.use((router) =>
79
+ router.get('*', HttpServerResponse.redirect('/404'))
80
+ );
81
+
82
+ /**
83
+ * Collection of API handlers for the new Effect HttpApi handlers
84
+ */
85
+ const APICollection = Layer.mergeAll(
86
+ AuthAPILive,
87
+ IntegrationsAPILive,
88
+ RestAPILive,
89
+ SDKAPILive,
90
+ DashboardAPILive,
91
+ CatchAllGroup
92
+ );
93
+
94
+ /**
95
+ * Combined API Layer - Combines the API handlers with the documentation route if enabled in the configuration.
96
+ *
97
+ * If the API documentation is enabled, it merges the DocsRouteLive layer with the APICollection layer to serve both the API endpoints and the documentation. If the documentation is disabled, it only serves the API endpoints.
98
+ */
99
+ const APILive: Layer.Layer<Api, never, never> = config.features.api.apiDocs
100
+ ? Layer.merge(DocsRouteLive, APICollection)
101
+ : APICollection;
102
+
103
+ /**
104
+ * Astro API Route - Converts the combined Effect API stack into an Astro route for serving the API documentation and endpoints.
105
+ */
106
+ export const ALL: APIRoute = HttpApiToAstroRoute(APILive);
@@ -0,0 +1,26 @@
1
+ import { AuthAPIError } from '@withstudiocms/api-spec/auth';
2
+ import { Effect } from 'effect';
3
+ import { isValidEmail } from '#schemas/external-schemas';
4
+
5
+ /**
6
+ * Utility service for authentication-related operations in the StudioCMS API.
7
+ */
8
+ export class AuthAPIUtils extends Effect.Service<AuthAPIUtils>()(
9
+ 'studiocms/routes/api/auth/shared/AuthAPIUtils',
10
+ {
11
+ effect: Effect.gen(function* () {
12
+ return {
13
+ validateEmail: (email: string) =>
14
+ Effect.try({
15
+ try: () => isValidEmail(email),
16
+ catch: () =>
17
+ new AuthAPIError({
18
+ error: 'Failed to validate email.',
19
+ }),
20
+ }),
21
+ };
22
+ }),
23
+ }
24
+ ) {
25
+ static Provide = Effect.provide(this.Default);
26
+ }
@@ -0,0 +1,147 @@
1
+ import { sdkClient } from 'studiocms:client/apiClients';
2
+ import { HTTPClient } from '@withstudiocms/effect';
3
+ import { loadChangelog, semverCategories } from '@withstudiocms/internal_helpers/utils';
4
+ import { Data, Effect, pipe } from 'effect';
5
+ import type { List, Root } from 'mdast';
6
+ import { toMarkdown } from 'mdast-util-to-markdown';
7
+
8
+ /**
9
+ * Custom error class used for quick escaping from deep error handling in the Effect chain.
10
+ */
11
+ export class ChangelogError extends Data.TaggedError('ChangelogError')<{ message: string }> {}
12
+
13
+ /**
14
+ * Service for processing the changelog of StudioCMS.
15
+ *
16
+ * This service fetches the raw changelog from the GitHub repository, processes it to extract relevant information, and renders it using a partial endpoint.
17
+ */
18
+ export class ProcessChangelog extends Effect.Service<ProcessChangelog>()('ProcessChangelog', {
19
+ effect: Effect.gen(function* () {
20
+ const httpClient = yield* HTTPClient;
21
+
22
+ /**
23
+ * Fetches the raw changelog markdown from the GitHub repository. If the fetch fails, it returns a ChangelogError with details about the failure.
24
+ */
25
+ const getRawChangelog = () =>
26
+ Effect.gen(function* () {
27
+ const data = yield* httpClient.get(
28
+ 'https://raw.githubusercontent.com/withstudiocms/studiocms/refs/heads/main/packages/studiocms/CHANGELOG.md'
29
+ );
30
+
31
+ if (data.status !== 200) {
32
+ return yield* new ChangelogError({
33
+ message: `Failed to fetch CHANGELOG.md: ${data.status} ${data.toString()}`,
34
+ });
35
+ }
36
+
37
+ return yield* data.text;
38
+ });
39
+
40
+ /**
41
+ * Processes the raw changelog markdown to extract version information and changes, and then converts it back to markdown format. If any step in the processing fails, it returns a ChangelogError with details about the failure.
42
+ * @param raw The raw changelog markdown content.
43
+ * @returns The processed changelog in markdown format.
44
+ * @throws ChangelogError if processing fails at any step.
45
+ *
46
+ */
47
+ const generateChangelog = (raw: string) =>
48
+ Effect.gen(function* () {
49
+ const ToProcess = yield* Effect.try(() => loadChangelog({ raw }));
50
+
51
+ const output: string[] = [];
52
+
53
+ const astEnd: Root = {
54
+ type: 'root',
55
+ children: [],
56
+ };
57
+
58
+ for (const version of ToProcess.versions) {
59
+ const versionChanges: List = { type: 'list', children: [] };
60
+
61
+ for (const semverCategory of semverCategories) {
62
+ for (const listItem of version.changes[semverCategory].children) {
63
+ versionChanges.children.push(listItem);
64
+ }
65
+ }
66
+
67
+ if (version.includes.size) {
68
+ versionChanges.children.push({
69
+ type: 'listItem',
70
+ children: [
71
+ {
72
+ type: 'paragraph',
73
+ children: [
74
+ { type: 'text', value: `Includes: ${[...version.includes].join(', ')} ` },
75
+ ],
76
+ },
77
+ ],
78
+ });
79
+ }
80
+
81
+ if (!versionChanges.children.length) continue;
82
+
83
+ astEnd.children.push({
84
+ type: 'heading',
85
+ depth: 2,
86
+ children: [{ type: 'text', value: version.version }],
87
+ });
88
+
89
+ astEnd.children.push(versionChanges);
90
+ }
91
+
92
+ const outputData = yield* Effect.try(() => toMarkdown(astEnd, { bullet: '-' }));
93
+
94
+ output.push(outputData);
95
+
96
+ const markdownString = output.join('\n');
97
+
98
+ return markdownString;
99
+ });
100
+
101
+ /**
102
+ * Renders the processed changelog markdown by sending it to a partial endpoint. If the rendering fails, it returns a ChangelogError with details about the failure.
103
+ *
104
+ * @param content The processed changelog markdown content to be rendered.
105
+ * @returns The rendered changelog content as returned by the partial endpoint.
106
+ */
107
+ const renderChangelog = (content: string) =>
108
+ Effect.gen(function* () {
109
+ const client = yield* sdkClient;
110
+
111
+ return yield* client.utils
112
+ .renderMarkdown({
113
+ payload: {
114
+ content,
115
+ },
116
+ urlParams: {},
117
+ })
118
+ .pipe(Effect.map((response) => response.html));
119
+ });
120
+
121
+ /**
122
+ * Runs the entire changelog processing pipeline, which includes fetching the raw changelog, generating the processed markdown, and rendering it. If any step in the pipeline fails, it returns a ChangelogError with details about the failure.
123
+ */
124
+ const runPipeline = () =>
125
+ pipe(
126
+ getRawChangelog(),
127
+ Effect.flatMap(generateChangelog),
128
+ Effect.flatMap(renderChangelog),
129
+ Effect.catchAll(
130
+ (error) =>
131
+ new ChangelogError({
132
+ message: `Failed to process changelog: ${error instanceof Error ? error.message : String(error)}`,
133
+ })
134
+ )
135
+ );
136
+
137
+ return {
138
+ getRawChangelog,
139
+ generateChangelog,
140
+ renderChangelog,
141
+ runPipeline,
142
+ };
143
+ }),
144
+ dependencies: [HTTPClient.Default],
145
+ }) {
146
+ static Provide = Effect.provide(this.Default);
147
+ }