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
@@ -0,0 +1,307 @@
1
+ import { Session, VerifyEmail } from 'studiocms:auth/lib';
2
+ import type { SessionValidationResult, UserSessionData } from 'studiocms:auth/lib/types';
3
+ import { developerConfig } from 'studiocms:config';
4
+ import { logger as _logger } from 'studiocms:logger';
5
+ import { SDKCore } from 'studiocms:sdk';
6
+ import routeConfig from 'virtual:studiocms/route-config';
7
+ import { HttpApiBuilder, HttpServerResponse } from '@effect/platform';
8
+ import { StudioCMSDashboardApiSpec } from '@withstudiocms/api-spec';
9
+ import { CurrentUser } from '@withstudiocms/api-spec/astro-context';
10
+ import { DashboardAPIError } from '@withstudiocms/api-spec/dashboard';
11
+ import { AstroAPIContext } from '@withstudiocms/effect';
12
+ import type { APIContext } from 'astro';
13
+ import { Effect } from 'effect';
14
+ import { AuthSessionCookieName } from '#consts';
15
+ import { sharedDBErrors, sharedNotifierErrors } from './_shared.js';
16
+
17
+ /**
18
+ * Check if the Dashboard API is enabled in the route configuration.
19
+ */
20
+ const dashboardAPIEnabled = routeConfig.dashboardAPIEnabled;
21
+
22
+ /**
23
+ * Response Data object for the verifySession endpoint. This defines the structure of the response that will be sent back to the client when verifying a user's session. It includes information about whether the user is logged in, their user details, permission level, and relevant route links for the dashboard.
24
+ */
25
+ type ResponseData = {
26
+ isLoggedIn: boolean;
27
+ user: {
28
+ id: string;
29
+ name: string;
30
+ email: string | null;
31
+ avatar: string | null;
32
+ username: string;
33
+ } | null;
34
+ permissionLevel: UserSessionData['permissionLevel'];
35
+ routes: {
36
+ logout: string;
37
+ userProfile: string;
38
+ contentManagement: string;
39
+ dashboardIndex: string;
40
+ };
41
+ };
42
+
43
+ /**
44
+ * Response builder for the verifySession endpoint. This function constructs a standardized response object containing the user's authentication status, user information, permission level, and relevant route links. It is used to provide consistent responses for session verification requests, allowing the frontend to easily determine the user's session state and permissions.
45
+ */
46
+ const responseBuilder = (
47
+ context: APIContext,
48
+ isLoggedIn: boolean,
49
+ user: SessionValidationResult['user'],
50
+ permissionLevel: UserSessionData['permissionLevel']
51
+ ) => {
52
+ const data: ResponseData = {
53
+ isLoggedIn,
54
+ user: user
55
+ ? {
56
+ id: user.id,
57
+ name: user.name,
58
+ email: user.email || null,
59
+ avatar: user.avatar || null,
60
+ username: user.username,
61
+ }
62
+ : null,
63
+ permissionLevel: permissionLevel,
64
+ routes: {
65
+ logout: context.locals.StudioCMS.routeMap.authLinks.logoutAPI,
66
+ userProfile: context.locals.StudioCMS.routeMap.mainLinks.userProfile,
67
+ contentManagement: context.locals.StudioCMS.routeMap.mainLinks.contentManagement,
68
+ dashboardIndex: context.locals.StudioCMS.routeMap.mainLinks.dashboardIndex,
69
+ },
70
+ };
71
+
72
+ return data;
73
+ };
74
+
75
+ /**
76
+ * Verify Endpoints Handlers for the Dashboard API
77
+ */
78
+ export const VerifyEndpointsHandlers = HttpApiBuilder.group(
79
+ StudioCMSDashboardApiSpec,
80
+ 'verifyEndpoints',
81
+ (handlers) =>
82
+ handlers
83
+ .handle(
84
+ 'verifyEmail',
85
+ Effect.fn(
86
+ function* ({ urlParams: { token, userId } }) {
87
+ if (!dashboardAPIEnabled) {
88
+ return yield* new DashboardAPIError({
89
+ error: 'Dashboard API is disabled, this action is not allowed.',
90
+ });
91
+ }
92
+
93
+ if (developerConfig.demoMode !== false) {
94
+ return yield* new DashboardAPIError({
95
+ error: 'Demo mode is enabled, this action is not allowed.',
96
+ });
97
+ }
98
+
99
+ const [sdk, verifyEmail, ctx] = yield* Effect.all([
100
+ SDKCore,
101
+ VerifyEmail,
102
+ AstroAPIContext,
103
+ ]);
104
+
105
+ const verificationToken = yield* verifyEmail.getEmailVerificationRequest(userId);
106
+
107
+ if (!verificationToken) {
108
+ return yield* new DashboardAPIError({
109
+ error: 'Verification token not found',
110
+ });
111
+ }
112
+
113
+ if (verificationToken.token !== token) {
114
+ return yield* new DashboardAPIError({
115
+ error: 'Invalid token',
116
+ });
117
+ }
118
+
119
+ const existingUser = yield* sdk.GET.users.byId(userId);
120
+
121
+ if (!existingUser) {
122
+ return yield* new DashboardAPIError({
123
+ error: 'User not found',
124
+ });
125
+ }
126
+
127
+ yield* Effect.all([
128
+ sdk.AUTH.user.update({
129
+ userId,
130
+ userData: {
131
+ id: userId,
132
+ name: existingUser.name,
133
+ username: existingUser.username,
134
+ emailVerified: true,
135
+ updatedAt: new Date().toISOString(),
136
+ createdAt: undefined,
137
+ },
138
+ }),
139
+ sdk.AUTH.verifyEmail.delete(userId),
140
+ ]);
141
+
142
+ if (!ctx.site) {
143
+ return yield* new DashboardAPIError({
144
+ error: 'Site configuration not found',
145
+ });
146
+ }
147
+
148
+ return HttpServerResponse.redirect(
149
+ new URL(ctx.locals.StudioCMS.routeMap.mainLinks.dashboardIndex, ctx.site?.toString())
150
+ );
151
+ },
152
+ VerifyEmail.Provide,
153
+ Effect.catchTags({
154
+ ...sharedDBErrors,
155
+ ...sharedNotifierErrors,
156
+ })
157
+ )
158
+ )
159
+ .handle(
160
+ 'verifySession',
161
+ Effect.fn(function* ({ payload: { originPathname } }) {
162
+ const [ses, sdk, ctx] = yield* Effect.all([
163
+ Session.pipe(
164
+ Effect.catchAll(
165
+ () => new DashboardAPIError({ error: 'Failed to initialize session' })
166
+ )
167
+ ),
168
+ SDKCore,
169
+ AstroAPIContext,
170
+ ]);
171
+
172
+ const logger = _logger.fork('studiocms:runtime:api:verify-session');
173
+
174
+ if (!dashboardAPIEnabled) {
175
+ return responseBuilder(ctx, false, null, 'unknown');
176
+ }
177
+
178
+ const { cookies } = ctx;
179
+
180
+ const sessionToken = cookies.get(AuthSessionCookieName)?.value ?? null;
181
+
182
+ if (!sessionToken) {
183
+ logger.info(
184
+ `No session token found in cookies, returning unknown session status. Origin: ${originPathname}`
185
+ );
186
+ return responseBuilder(ctx, false, null, 'unknown');
187
+ }
188
+
189
+ const { session, user } = yield* ses
190
+ .validateSessionToken(sessionToken)
191
+ .pipe(
192
+ Effect.catchAll(
193
+ () => new DashboardAPIError({ error: 'Failed to validate session token' })
194
+ )
195
+ );
196
+
197
+ if (session === null) {
198
+ yield* ses.deleteSessionTokenCookie(ctx).pipe(
199
+ Effect.catchAll(
200
+ () =>
201
+ new DashboardAPIError({
202
+ error: 'Failed to delete invalid session token cookie',
203
+ })
204
+ )
205
+ );
206
+ logger.info(
207
+ `Session token is invalid or expired, deleting cookie. Origin: ${originPathname}`
208
+ );
209
+ return responseBuilder(ctx, false, null, 'unknown');
210
+ }
211
+
212
+ if (!user || user === null) {
213
+ logger.info(
214
+ `No user found for session token, returning unknown session status. Origin: ${originPathname}`
215
+ );
216
+ return responseBuilder(ctx, false, null, 'unknown');
217
+ }
218
+
219
+ const result = yield* sdk.AUTH.permission.currentStatus(user.id);
220
+
221
+ if (!result) {
222
+ logger.error(
223
+ `Failed to retrieve permission status for user ${user.id}, returning unknown session status. Origin: ${originPathname}`
224
+ );
225
+ return responseBuilder(ctx, true, user, 'unknown');
226
+ }
227
+
228
+ const permissionLevel: UserSessionData['permissionLevel'] = result.rank;
229
+ return responseBuilder(ctx, true, user, permissionLevel);
230
+ }, Effect.catchTags(sharedDBErrors))
231
+ )
232
+ .handle(
233
+ 'resendVerifyEmail',
234
+ Effect.fn(
235
+ function* ({ payload: { userId } }) {
236
+ if (!dashboardAPIEnabled) {
237
+ return yield* new DashboardAPIError({
238
+ error: 'Dashboard API is disabled, this action is not allowed.',
239
+ });
240
+ }
241
+
242
+ if (developerConfig.demoMode !== false) {
243
+ return yield* new DashboardAPIError({
244
+ error: 'Demo mode is enabled, this action is not allowed.',
245
+ });
246
+ }
247
+
248
+ const [sdk, verifier, ctx, userData] = yield* Effect.all([
249
+ SDKCore,
250
+ VerifyEmail,
251
+ AstroAPIContext,
252
+ CurrentUser,
253
+ ]);
254
+
255
+ if (!ctx.locals.StudioCMS.siteConfig.data.enableMailer) {
256
+ return yield* new DashboardAPIError({
257
+ error: 'Mailer is disabled, this action is disabled.',
258
+ });
259
+ }
260
+
261
+ if (!userData.isLoggedIn || !userData.userPermissionLevel.isAdmin) {
262
+ return yield* new DashboardAPIError({
263
+ error: 'Unauthorized',
264
+ });
265
+ }
266
+
267
+ const newToken = yield* sdk.AUTH.verifyEmail.create(userId);
268
+
269
+ if (!newToken) {
270
+ return yield* new DashboardAPIError({
271
+ error: 'Failed to create verification token',
272
+ });
273
+ }
274
+
275
+ const response = yield* verifier
276
+ .sendVerificationEmail(userId)
277
+ .pipe(
278
+ Effect.catchAll(
279
+ () => new DashboardAPIError({ error: 'Failed to send verification email' })
280
+ )
281
+ );
282
+
283
+ if (!response) {
284
+ return yield* new DashboardAPIError({
285
+ error: 'Failed to send verification email',
286
+ });
287
+ }
288
+
289
+ if ('error' in response) {
290
+ return yield* new DashboardAPIError({
291
+ error: response.error,
292
+ });
293
+ }
294
+
295
+ return {
296
+ message: response.message,
297
+ };
298
+ },
299
+ VerifyEmail.Provide,
300
+ Effect.catchTags({
301
+ ...sharedDBErrors,
302
+ ...sharedNotifierErrors,
303
+ GeneratorError: () => new DashboardAPIError({ error: 'An unknown error occurred' }),
304
+ })
305
+ )
306
+ )
307
+ );
@@ -0,0 +1,98 @@
1
+ import config from 'studiocms:config';
2
+ import { HttpApiBuilder } from '@effect/platform';
3
+ import { Unauthorized } from '@effect/platform/HttpApiError';
4
+ import { CurrentUser } from '@withstudiocms/api-spec/astro-context';
5
+ import {
6
+ DbStudioQueryError,
7
+ IntegrationsAPIError,
8
+ StudioCMSIntegrationsApiSpec,
9
+ } from '@withstudiocms/api-spec/integrations';
10
+ import { CMSLogger } from '@withstudiocms/effect';
11
+ import { Effect, Layer } from 'effect';
12
+ import { AstroLocalsAuthLive } from '../../_middleware/astroLocals.js';
13
+ import { getDriverInstance } from '../_utils/db-studio-driver.js';
14
+ import { parseLogLevel } from '../_utils/parseLogLevel.js';
15
+
16
+ /**
17
+ * Custom error class used for quick escaping from deep error handling in the Effect chain.
18
+ */
19
+ export class QuickEscapeError {
20
+ readonly _tag = 'QuickEscapeError';
21
+ constructor(public data: typeof DbStudioQueryError.Type) {}
22
+ }
23
+
24
+ /**
25
+ * DB Studio API Handler.
26
+ *
27
+ * This handler manages the API routes for the DB Studio, including database queries and storage management.
28
+ */
29
+ export const DbStudioAPIHandler = HttpApiBuilder.group(
30
+ StudioCMSIntegrationsApiSpec,
31
+ 'dbStudio',
32
+ (handlers) =>
33
+ handlers.handle(
34
+ 'dbStudioQuery',
35
+ Effect.fn(function* ({ payload }) {
36
+ const isDev = import.meta.env.DEV;
37
+
38
+ const logLevel = parseLogLevel(config.logLevel);
39
+
40
+ const log = new CMSLogger({ level: logLevel }, 'studiocms:database/studio');
41
+
42
+ // Check if demo mode is enabled
43
+ if (config.features.developerConfig.demoMode !== false) {
44
+ return yield* new Unauthorized();
45
+ }
46
+
47
+ const currentUser = yield* CurrentUser;
48
+
49
+ // Security check: only allow access in the following cases
50
+ // 1. In development mode
51
+ // 2. In production, only if the user is an owner
52
+ if (!isDev && currentUser.permissionLevel !== 'owner') {
53
+ return yield* new Unauthorized();
54
+ }
55
+
56
+ // Get the database driver instance
57
+ const driver = yield* getDriverInstance().pipe(
58
+ Effect.catchTag(
59
+ 'DriverError',
60
+ (error) =>
61
+ new IntegrationsAPIError({
62
+ error: `Failed to get database driver: ${error.message}`,
63
+ })
64
+ )
65
+ );
66
+
67
+ log.debug(`Received ${payload.type} request`);
68
+
69
+ return yield* Effect.tryPromise({
70
+ try: async () => {
71
+ if (payload.type === 'query') {
72
+ const r = await driver.query(payload.statement);
73
+ return {
74
+ type: payload.type,
75
+ id: payload.id,
76
+ data: r,
77
+ };
78
+ }
79
+ const r = await driver.batch(payload.statements as string[]);
80
+ log.debug(`${payload.type} executed with ${r.length} results`);
81
+ return {
82
+ type: payload.type,
83
+ id: payload.id,
84
+ data: r,
85
+ };
86
+ },
87
+ catch: (cause) =>
88
+ new QuickEscapeError(
89
+ DbStudioQueryError.make({
90
+ id: payload.id,
91
+ type: payload.type,
92
+ error: cause instanceof Error ? cause.message : String(cause),
93
+ })
94
+ ),
95
+ }).pipe(Effect.catchTag('QuickEscapeError', ({ data }) => Effect.succeed(data)));
96
+ })
97
+ )
98
+ ).pipe(Layer.provide(AstroLocalsAuthLive));
@@ -0,0 +1,17 @@
1
+ import { HttpApiBuilder } from '@effect/platform';
2
+ import { StudioCMSIntegrationsApiSpec } from '@withstudiocms/api-spec';
3
+ import { Layer } from 'effect';
4
+ import { DbStudioAPIHandler } from './dbStudio.js';
5
+ import { StorageManagerAPIHandler } from './storageManager.js';
6
+
7
+ /**
8
+ * Combined Integrations API Handler.
9
+ */
10
+ export const IntegrationsAPIHandler = Layer.merge(DbStudioAPIHandler, StorageManagerAPIHandler);
11
+
12
+ /**
13
+ * Live implementation of the Integrations API Handler.
14
+ */
15
+ export const IntegrationsAPILive = HttpApiBuilder.api(StudioCMSIntegrationsApiSpec).pipe(
16
+ Layer.provide(IntegrationsAPIHandler)
17
+ );
@@ -0,0 +1,107 @@
1
+ import APIServiceModule from 'studiocms:storage-manager/module';
2
+ import { HttpApiBuilder, type HttpServerResponse } from '@effect/platform';
3
+ import type { HttpBodyError } from '@effect/platform/HttpBody';
4
+ import { StudioCMSIntegrationsApiSpec } from '@withstudiocms/api-spec';
5
+ import { AstroAPIContext } from '@withstudiocms/api-spec/astro-context';
6
+ import { IntegrationsAPIError } from '@withstudiocms/api-spec/integrations';
7
+ import type { APIContext } from 'astro';
8
+ import { Effect, Layer } from 'effect';
9
+ import type { StorageAPIEndpointFn } from '#storage-api';
10
+ import APICore from '#storage-manager/core/api-core';
11
+ import UrlMappingDatabase from '#storage-manager/core/database';
12
+ import EffectifyAstroContextDriver from '#storage-manager/core/effectify-astro-context';
13
+ import UrlMappingService from '#storage-manager/core/url-mapping';
14
+ import { AstroLocalsAuthLive } from '../../_middleware/astroLocals.js';
15
+
16
+ // Singleton instance of the API core
17
+ let apiCore: APICore<
18
+ APIContext,
19
+ Effect.Effect<HttpServerResponse.HttpServerResponse, HttpBodyError>
20
+ >;
21
+
22
+ /**
23
+ * Retrieves the singleton instance of the APICore.
24
+ *
25
+ * This function initializes the APICore instance if it hasn't been created yet,
26
+ * setting up the necessary context driver, URL mapping service, and API service module.
27
+ *
28
+ * @returns The singleton APICore instance.
29
+ */
30
+ function getAPICore() {
31
+ if (apiCore) {
32
+ return apiCore;
33
+ }
34
+
35
+ // Instantiate the Effectify Astro context driver
36
+ const effectifyAstroContextDriver = new EffectifyAstroContextDriver();
37
+
38
+ // Instantiate the database
39
+ const database = new UrlMappingDatabase();
40
+
41
+ // Instantiate the URL mapping service
42
+ const urlMappingService = new UrlMappingService(database);
43
+
44
+ // Instantiate the API service module
45
+ const apiService = new APIServiceModule(effectifyAstroContextDriver, urlMappingService);
46
+
47
+ // Instantiate the API core
48
+ apiCore = new APICore({
49
+ driver: effectifyAstroContextDriver,
50
+ urlMappingService: urlMappingService,
51
+ storageDriver: apiService,
52
+ });
53
+
54
+ return apiCore;
55
+ }
56
+
57
+ /**
58
+ * Helper function to create storage manager handlers with consistent error handling.
59
+ *
60
+ * This function takes a StorageAPIEndpointFn and returns a handler function that processes the request
61
+ * using the APICore instance. It includes error handling to catch and transform errors into a consistent format.
62
+ *
63
+ * @param _try - The StorageAPIEndpointFn to execute for the request.
64
+ * @returns A function that handles the API request and returns an Effect with the response or error.
65
+ */
66
+ const makeStorageManagerHandler = (
67
+ _try: StorageAPIEndpointFn<
68
+ APIContext,
69
+ Effect.Effect<HttpServerResponse.HttpServerResponse, HttpBodyError, never>
70
+ >
71
+ ) =>
72
+ AstroAPIContext.pipe(
73
+ Effect.flatMap((ctx) =>
74
+ Effect.tryPromise({
75
+ try: () => _try(ctx),
76
+ catch: (error) =>
77
+ new IntegrationsAPIError({
78
+ error: `Failed to handle storage manager request: ${error instanceof Error ? error.message : String(error)}`,
79
+ }),
80
+ })
81
+ ),
82
+ Effect.flatten,
83
+ Effect.catchTag(
84
+ 'HttpBodyError',
85
+ () =>
86
+ new IntegrationsAPIError({
87
+ error: 'Failed to parse request body',
88
+ })
89
+ )
90
+ );
91
+
92
+ /**
93
+ * Storage Manager API Handler.
94
+ *
95
+ * This handler manages the API routes for storage management, including database queries and storage operations.
96
+ * It uses the APICore to handle storage-related requests and includes error handling for various failure scenarios.
97
+ */
98
+ export const StorageManagerAPIHandler = HttpApiBuilder.group(
99
+ StudioCMSIntegrationsApiSpec,
100
+ 'storageManager',
101
+ (handlers) =>
102
+ handlers
103
+ .handleRaw('storageManager', () => makeStorageManagerHandler(getAPICore().getPOST('locals')))
104
+ .handleRaw('storageManagerUpload', () =>
105
+ makeStorageManagerHandler(getAPICore().getPUT('locals'))
106
+ )
107
+ ).pipe(Layer.provide(AstroLocalsAuthLive));
@@ -0,0 +1,8 @@
1
+ import { RestAPIV1Live } from './v1/index.js';
2
+
3
+ /**
4
+ * Live REST API Handler Layer - Provides the REST API with all necessary dependencies for live operation.
5
+ *
6
+ * For now, We just re-export the V1 live handler, but in the future, this can be expanded to include additional versions
7
+ */
8
+ export const RestAPILive = RestAPIV1Live;
@@ -0,0 +1,41 @@
1
+ import { RestAPIError } from '@withstudiocms/api-spec/rest-api';
2
+
3
+ /**
4
+ * Shared database error handlers for the REST API. These handlers convert common database-related errors into consistent RestAPIError responses, allowing for cleaner and more maintainable error handling across all endpoints that interact with the database.
5
+ */
6
+ export const sharedDBErrors = {
7
+ DBCallbackFailure: () => new RestAPIError({ error: 'Database callback failed' }),
8
+ DBClientInitializationError: () =>
9
+ new RestAPIError({ error: 'Database client initialization failed' }),
10
+ NotFoundError: () => new RestAPIError({ error: 'Resource not found' }),
11
+ QueryError: () => new RestAPIError({ error: 'Database query failed' }),
12
+ QueryParseError: () => new RestAPIError({ error: 'Database query parsing failed' }),
13
+ SDKInitializationError: () => new RestAPIError({ error: 'SDK initialization failed' }),
14
+ };
15
+
16
+ /**
17
+ * Shared notification error handlers for the REST API. These handlers convert common notification-related errors into consistent RestAPIError responses, allowing for cleaner and more maintainable error handling across all endpoints that involve sending notifications.
18
+ */
19
+ export const sharedNotifierErrors = {
20
+ ConfigError: () => new RestAPIError({ error: 'Configuration error during notification sending' }),
21
+ SMTPError: () => new RestAPIError({ error: 'SMTP error during notification sending' }),
22
+ UnknownException: () =>
23
+ new RestAPIError({ error: 'An unknown error occurred during notification sending' }),
24
+ };
25
+
26
+ /**
27
+ * Shared page collection error handlers for the REST API. These handlers convert common errors that can occur during the collection of pages for operations like category deletion into consistent RestAPIError responses, allowing for cleaner and more maintainable error handling in endpoints that involve complex data collection and manipulation.
28
+ */
29
+ export const sharedPageCollectionErrors = {
30
+ ParseError: () => new RestAPIError({ error: 'Failed to parse data during page collection' }),
31
+ FolderTreeError: () =>
32
+ new RestAPIError({
33
+ error: 'Failed to retrieve folder tree during page collection',
34
+ }),
35
+ CollectorError: () =>
36
+ new RestAPIError({
37
+ error: 'Failed to collect necessary data during page collection',
38
+ }),
39
+ PaginateError: () =>
40
+ new RestAPIError({ error: 'Failed to paginate data during page collection' }),
41
+ };
@@ -0,0 +1,17 @@
1
+ import { HttpApiBuilder } from '@effect/platform';
2
+ import { StudioCMSRestApiV1Spec } from '@withstudiocms/api-spec';
3
+ import { Layer } from 'effect';
4
+ import { RestApiPublicHandler } from './public.js';
5
+ import { RestApiSecureHandler } from './secure.js';
6
+
7
+ /**
8
+ * Collection of REST API handlers for the new Effect HttpApi handlers. This collection currently includes both public and secure handlers for REST API v1, but can be expanded in the future to include additional versions or handler groups as needed.
9
+ */
10
+ const RestAPILayers = Layer.merge(RestApiPublicHandler, RestApiSecureHandler);
11
+
12
+ /**
13
+ * Live REST API V1 Handler Layer - Provides the REST API with all necessary dependencies for live operation.
14
+ */
15
+ export const RestAPIV1Live = HttpApiBuilder.api(StudioCMSRestApiV1Spec).pipe(
16
+ Layer.provide(RestAPILayers)
17
+ );