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
@@ -12,23 +12,55 @@
12
12
 
13
13
  import crypto from 'node:crypto';
14
14
  import { User, VerifyEmail } from 'studiocms:auth/lib';
15
- import { dashboardConfig } from 'studiocms:config';
15
+ import config, { dashboardConfig } from 'studiocms:config';
16
16
  import { defaultLang } from 'studiocms:i18n';
17
17
  import { StudioCMSRoutes } from 'studiocms:lib';
18
18
  import { SDKCore } from 'studiocms:sdk';
19
19
  import SCMSUiVersion from 'studiocms:ui/version';
20
20
  import SCMSVersion from 'studiocms:version';
21
- import { defineMiddlewareRouter, Effect } from '@withstudiocms/effect';
22
- import micromatch from 'micromatch';
21
+ import {
22
+ Config,
23
+ defineDataMiddleware,
24
+ defineMiddlewareRouter,
25
+ Effect,
26
+ Layer,
27
+ Logger,
28
+ type LogLevel,
29
+ MiddlewareError,
30
+ Schema,
31
+ } from '@withstudiocms/effect';
23
32
  import { STUDIOCMS_EDITOR_CSRF_COOKIE_NAME } from '#consts';
24
- import { authenticatedRoutes } from './_authmap.js';
25
33
  import { getUserPermissions, makeFallbackSiteConfig, SetLocal, setLocals } from './utils.js';
26
34
 
35
+ // Load the log level from the configuration and apply it as a layer
36
+ const LogLevelLive = Config.withDefault(
37
+ Config.logLevel('STUDIOCMS_LOGLEVEL'),
38
+ config.logLevel
39
+ ).pipe(
40
+ Effect.tap((level) => Effect.log(`StudioCMS Middleware Log Level set to: ${level}`)),
41
+ Effect.andThen((level) =>
42
+ // Set the minimum log level
43
+ Logger.minimumLogLevel(level as LogLevel.LogLevel)
44
+ ),
45
+ Layer.unwrapEffect, // Convert the effect into a layer
46
+ Layer.provide(Logger.pretty) // Ensure that the Logger.pretty layer is included
47
+ );
48
+
27
49
  // Import the dashboard route override from the configuration
28
50
  // If no override is set, it defaults to 'dashboard'
29
51
  // This allows for flexibility in the dashboard route without hardcoding it
30
52
  const dashboardRoute = dashboardConfig.dashboardRouteOverride || 'dashboard';
31
53
 
54
+ /**
55
+ * Helper function to create a standard 200 OK response.
56
+ *
57
+ * This function is used to return a successful response from the middleware when access is granted.
58
+ * It simplifies the response creation process and ensures consistency across the middleware handlers.
59
+ *
60
+ * @returns A Response object with a 200 OK status.
61
+ */
62
+ const okResponse = () => new Response(null, { status: 200 });
63
+
32
64
  /**
33
65
  * Main middleware sequence for StudioCMS.
34
66
  *
@@ -114,12 +146,6 @@ export const onRequest = defineMiddlewareRouter([
114
146
  }),
115
147
  },
116
148
  {
117
- /**
118
- * Middleware function to handle user authentication for the dashboard.
119
- * This middleware checks if the user is logged in and redirects to the login page if not
120
- * authenticated. It also excludes certain paths from this check, such as login, signup,
121
- * logout, and forgot password routes.
122
- */
123
149
  includePaths: [`/${dashboardRoute}/**`],
124
150
  excludePaths: [
125
151
  `/${dashboardRoute}/login`,
@@ -134,66 +160,81 @@ export const onRequest = defineMiddlewareRouter([
134
160
  `/${dashboardRoute}/password-reset/**`,
135
161
  ],
136
162
  priority: 3,
137
- handler: Effect.fn(function* (context, next) {
138
- const getUserData = yield* Effect.gen(function* () {
139
- const { getUserData } = yield* User;
140
- return getUserData;
141
- });
163
+ handler: defineDataMiddleware(
164
+ Schema.Struct({
165
+ 'x-required-role': Schema.optional(
166
+ Schema.Literal('owner', 'admin', 'editor', 'visitor', 'none')
167
+ ),
168
+ 'x-redirect-url': Schema.optional(Schema.String),
169
+ }),
170
+ Effect.fn(
171
+ function* (context, data) {
172
+ const getUserData = (yield* User).getUserData;
142
173
 
143
- // Retrieve the user session data from the context locals or fetch it
144
- const userSessionData =
145
- context.locals.StudioCMS.security?.userSessionData ?? (yield* getUserData(context));
174
+ yield* Effect.logDebug('Data middleware received headers:', data);
146
175
 
147
- // Check if the user is logged in and redirect to the login page if not
148
- if (!userSessionData.isLoggedIn) return context.redirect(StudioCMSRoutes.authLinks.loginURL);
176
+ // Get the required role from the headers, defaulting to 'none' if not provided
177
+ // This is an 'Opt-in' Middleware
178
+ const requiredRole = data['x-required-role'] ?? 'none';
179
+ const redirectUrl = data['x-redirect-url'] ?? `/${dashboardRoute}`;
149
180
 
150
- // Get the current path
151
- const currentPath = context.url.pathname;
181
+ // If the required role is 'none', allow access without checking user data
182
+ if (requiredRole === 'none') {
183
+ yield* Effect.logDebug(
184
+ 'No required role specified, allowing access without authentication'
185
+ );
186
+ return okResponse();
187
+ }
152
188
 
153
- // Check if the user has permission to access the current route
154
- // If not, redirect to the dashboard home page
155
- const userPermissionLevel =
156
- context.locals.StudioCMS.security?.userSessionData.permissionLevel;
189
+ // Retrieve the user session data from the context locals or fetch it
190
+ const userSessionData =
191
+ context.locals.StudioCMS.security?.userSessionData ?? (yield* getUserData(context));
157
192
 
158
- if (!userPermissionLevel) {
159
- // How did the user get here? Log them out to reset session
160
- return context.redirect(`/${dashboardRoute}/logout`);
161
- }
193
+ if (!userSessionData.isLoggedIn) {
194
+ yield* Effect.logDebug('User is not logged in, redirecting to login page');
195
+ return context.redirect(StudioCMSRoutes.authLinks.loginURL);
196
+ }
197
+
198
+ yield* Effect.logDebug(
199
+ 'User is logged in, checking permissions for required role:',
200
+ requiredRole
201
+ );
162
202
 
163
- // Using micromatch to handle wildcard route matching
164
- const matchChance1 = authenticatedRoutes.find((route) =>
165
- micromatch.isMatch(currentPath, route.pathname)
166
- );
167
-
168
- // if trailing `/` exists, try matching without it
169
- const matchChance2 =
170
- matchChance1 ||
171
- (() => {
172
- if (currentPath.endsWith('/')) {
173
- const trimmedPath = currentPath.slice(0, -1);
174
- return authenticatedRoutes.find((route) =>
175
- micromatch.isMatch(trimmedPath, route.pathname)
203
+ const userPermissionLevel = userSessionData.permissionLevel;
204
+
205
+ if (!userPermissionLevel) {
206
+ yield* Effect.logDebug(
207
+ 'User permission level is missing, redirecting to logout to reset session'
176
208
  );
209
+ // How did the user get here? Log them out to reset session
210
+ return context.redirect(`/${dashboardRoute}/logout`);
177
211
  }
178
- return null;
179
- })();
180
-
181
- if (matchChance1 || matchChance2) {
182
- // biome-ignore lint/style/noNonNullAssertion: only used after checking for existence
183
- const matchingRoute = matchChance1 || matchChance2!;
184
- const requiredLevel = matchingRoute.requiredPermissionLevel;
185
- const levels = ['visitor', 'editor', 'admin', 'owner'];
186
- const userLevelIndex = levels.indexOf(userPermissionLevel);
187
- const requiredLevelIndex = levels.indexOf(requiredLevel);
188
-
189
- if (userLevelIndex < requiredLevelIndex) {
190
- return context.redirect(`/${dashboardRoute}`);
191
- }
192
- }
193
212
 
194
- // Else, Continue to the next middleware
195
- return next();
196
- }),
213
+ yield* Effect.logDebug(
214
+ `User permission level: ${userPermissionLevel}, required role: ${requiredRole}`
215
+ );
216
+
217
+ const levels = ['visitor', 'editor', 'admin', 'owner'];
218
+ const userLevelIndex = levels.indexOf(userPermissionLevel);
219
+ const requiredLevelIndex = levels.indexOf(requiredRole);
220
+
221
+ if (userLevelIndex < requiredLevelIndex) {
222
+ yield* Effect.logDebug(
223
+ `User does not have required permissions (user level: ${userPermissionLevel}, required level: ${requiredRole}), redirecting to:`,
224
+ redirectUrl
225
+ );
226
+ return context.redirect(redirectUrl);
227
+ }
228
+
229
+ yield* Effect.logDebug('User has required permissions, allowing access');
230
+ return okResponse();
231
+ },
232
+ Effect.provide(LogLevelLive),
233
+ Effect.catchAll(
234
+ (cause) => new MiddlewareError({ message: 'Failed to get user data', cause })
235
+ )
236
+ )
237
+ ),
197
238
  },
198
239
  {
199
240
  /**
@@ -1,25 +1,21 @@
1
1
  ---
2
+ import { config } from 'studiocms:config';
2
3
  import '../styles/404.css';
3
4
  import { useTranslations } from 'studiocms:i18n';
4
5
  import { Button } from 'studiocms:ui/components/button';
5
6
  import Layout from '../layouts/DashboardLayout.astro';
6
7
 
7
- const lang = Astro.locals.StudioCMS.defaultLang;
8
+ const lang = config.locale.i18n.defaultLocale;
8
9
  const t = useTranslations(lang, '@studiocms/dashboard:404');
9
-
10
- const { siteConfig: config, security } = Astro.locals.StudioCMS;
11
-
12
- const currentUser = security?.userSessionData ?? null;
13
10
  ---
14
11
 
15
12
  <Layout
16
13
  title={t('title')}
17
14
  description={t('description')}
18
15
  sidebar={false}
19
- requiredPermission="none"
20
- {lang}
21
- {config}
22
- {currentUser}>
16
+ config={{ data: { title: t('title'), description: t('description') }, id: '' }}
17
+ currentUser={null}
18
+ {lang}>
23
19
  <div class="notfound-container">
24
20
  <div class="notfound">
25
21
  <svg viewBox="0 0 755 792" fill="none" xmlns="http://www.w3.org/2000/svg">
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  import { getPluginDashboardPages } from 'studiocms:plugin-helpers';
3
+ import { setDataContext } from '@withstudiocms/effect/astro/data-middleware';
3
4
  import type { FinalDashboardPage } from '#schemas';
4
5
  import PageHeader from '../../components/dashboard/PageHeader.astro';
5
6
  import Layout from '../../layouts/DashboardLayout.astro';
@@ -43,12 +44,20 @@ const {
43
44
 
44
45
  // Check if the sidebar is double and if the InnerSidebarComponent exists to determine the sidebar configuration
45
46
  const sidebarConfig = sidebar === 'double' && InnerSidebarComponent ? 'double' : 'single';
47
+
48
+ setDataContext(Astro, {
49
+ key: 'x-required-role',
50
+ value: requiredPermissions,
51
+ });
52
+ setDataContext(Astro, {
53
+ key: 'x-redirect-url',
54
+ value: Astro.locals.StudioCMS.routeMap.mainLinks.dashboardIndex,
55
+ });
46
56
  ---
47
57
 
48
58
  <Layout
49
59
  title={title[lang]}
50
60
  description={description}
51
- requiredPermission={requiredPermissions}
52
61
  sidebar={sidebarConfig}
53
62
  {lang}
54
63
  {config}
@@ -2,6 +2,7 @@
2
2
  import { useTranslations } from 'studiocms:i18n';
3
3
  import { Button } from 'studiocms:ui/components/button';
4
4
  import { Icon } from 'studiocms:ui/components/icon';
5
+ import { setDataContext } from '@withstudiocms/effect/astro/data-middleware';
5
6
  import BrowserInputArray from '#frontend/components/shared/storage-manager/BrowserInputArray.astro';
6
7
  import ConfigForm from '../../components/dashboard/configuration/ConfigForm.astro';
7
8
  import PageHeader from '../../components/dashboard/PageHeader.astro';
@@ -12,12 +13,20 @@ const { siteConfig: config, defaultLang: lang, security } = Astro.locals.StudioC
12
13
  const currentUser = security?.userSessionData ?? null;
13
14
 
14
15
  const t = useTranslations(lang, '@studiocms/dashboard:configuration');
16
+
17
+ setDataContext(Astro, {
18
+ key: 'x-required-role',
19
+ value: 'owner',
20
+ });
21
+ setDataContext(Astro, {
22
+ key: 'x-redirect-url',
23
+ value: Astro.locals.StudioCMS.routeMap.mainLinks.dashboardIndex,
24
+ });
15
25
  ---
16
26
 
17
27
  <Layout
18
28
  title={t('title')}
19
29
  description={t('description')}
20
- requiredPermission='owner'
21
30
  {lang}
22
31
  {config}
23
32
  {currentUser}
@@ -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 CreateFolder from '../../../components/dashboard/content-mgmt/CreateFolder.astro';
4
5
  import InnerSidebarElement from '../../../components/dashboard/content-mgmt/InnerSidebarElement.astro';
5
6
  import PageHeader from '../../../components/dashboard/content-mgmt/PageHeader.astro';
@@ -10,12 +11,20 @@ const { siteConfig: config, defaultLang: lang, security } = Astro.locals.StudioC
10
11
  const currentUser = security?.userSessionData ?? null;
11
12
 
12
13
  const t = useTranslations(lang, '@studiocms/dashboard:content-index');
14
+
15
+ setDataContext(Astro, {
16
+ key: 'x-required-role',
17
+ value: 'editor',
18
+ });
19
+ setDataContext(Astro, {
20
+ key: 'x-redirect-url',
21
+ value: Astro.locals.StudioCMS.routeMap.mainLinks.dashboardIndex,
22
+ });
13
23
  ---
14
24
 
15
25
  <Layout
16
26
  title={t('title')}
17
27
  description={t('description')}
18
- requiredPermission='editor'
19
28
  sidebar='double'
20
29
  {lang}
21
30
  {config}
@@ -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 BrowserInputArray from '#frontend/components/shared/storage-manager/BrowserInputArray.astro';
4
5
  import CreatePage from '../../../components/dashboard/content-mgmt/CreatePage.astro';
5
6
  import InnerSidebarElement from '../../../components/dashboard/content-mgmt/InnerSidebarElement.astro';
@@ -11,12 +12,20 @@ const { siteConfig: config, defaultLang: lang, security } = Astro.locals.StudioC
11
12
  const currentUser = security?.userSessionData ?? null;
12
13
 
13
14
  const t = useTranslations(lang, '@studiocms/dashboard:content-index');
15
+
16
+ setDataContext(Astro, {
17
+ key: 'x-required-role',
18
+ value: 'editor',
19
+ });
20
+ setDataContext(Astro, {
21
+ key: 'x-redirect-url',
22
+ value: Astro.locals.StudioCMS.routeMap.mainLinks.dashboardIndex,
23
+ });
14
24
  ---
15
25
 
16
26
  <Layout
17
27
  title={t('title')}
18
28
  description={t('description')}
19
- requiredPermission='editor'
20
29
  sidebar='double'
21
30
  {lang}
22
31
  {config}
@@ -7,6 +7,7 @@ import { Card } from 'studiocms:ui/components/card';
7
7
  import { Group } from 'studiocms:ui/components/group';
8
8
  import { Input } from 'studiocms:ui/components/input';
9
9
  import { Effect, genLogger, runEffect } from '@withstudiocms/effect';
10
+ import { setDataContext } from '@withstudiocms/effect/astro/data-middleware';
10
11
  import InnerSidebarElement from '../../../components/dashboard/content-mgmt/InnerSidebarElement.astro';
11
12
  import PageHeader from '../../../components/dashboard/content-mgmt/PageHeader.astro';
12
13
  import Layout from '../../../layouts/DashboardLayout.astro';
@@ -52,12 +53,20 @@ const [page, metaDataChanges, diffContentHTML] = await runEffect(
52
53
  );
53
54
 
54
55
  if (!page) return new Response(null, { status: 404 });
56
+
57
+ setDataContext(Astro, {
58
+ key: 'x-required-role',
59
+ value: 'editor',
60
+ });
61
+ setDataContext(Astro, {
62
+ key: 'x-redirect-url',
63
+ value: Astro.locals.StudioCMS.routeMap.mainLinks.dashboardIndex,
64
+ });
55
65
  ---
56
66
 
57
67
  <Layout
58
68
  title={t("title")}
59
69
  description={t("description")}
60
- requiredPermission="editor"
61
70
  sidebar="double"
62
71
  {lang}
63
72
  {config}
@@ -180,6 +189,8 @@ if (!page) return new Response(null, { status: 404 });
180
189
 
181
190
  <script>
182
191
  import { toast } from "studiocms:ui/components/toaster/client";
192
+ import { dashboardClient, dashboardSharedCatchTags } from "studiocms:client/apiClients";
193
+ import * as Effect from "effect/Effect";
183
194
 
184
195
  const revertMetaData = document.getElementById(
185
196
  "revert-metadata",
@@ -206,29 +217,43 @@ if (!page) return new Response(null, { status: 404 });
206
217
  return;
207
218
  }
208
219
 
209
- const response = await fetch(url, {
210
- headers: {
211
- "Content-Type": "application/json",
212
- },
213
- method: "POST",
214
- body: JSON.stringify({ id, type }),
215
- });
216
-
217
- const res = await response.json();
220
+ function isAllowedType(type: string): type is "data" | "content" | "both" {
221
+ return ["data", "content", "both"].includes(type);
222
+ }
218
223
 
219
- if (response.status !== 200) {
224
+ if (!isAllowedType(type)) {
220
225
  toast({
221
226
  title: "Error",
222
- description: res.error,
227
+ description: "Invalid revert type.",
223
228
  type: "danger",
224
229
  });
225
230
  return;
226
231
  }
227
232
 
228
- if (response.status === 200) {
233
+ const response = await dashboardClient.pipe(
234
+ Effect.flatMap((client) =>
235
+ client.content.revertToDiff({
236
+ payload: {
237
+ id,
238
+ type,
239
+ }
240
+ })
241
+ ),
242
+ Effect.catchTags(dashboardSharedCatchTags),
243
+ Effect.runPromise
244
+ );
245
+
246
+ if ("error" in response) {
247
+ toast({
248
+ title: "Error",
249
+ description: response.error,
250
+ type: "danger",
251
+ });
252
+ return;
253
+ } else {
229
254
  toast({
230
255
  title: "Success",
231
- description: res.message,
256
+ description: "Changes have been reverted successfully.",
232
257
  type: "success",
233
258
  });
234
259
  return;
@@ -2,6 +2,7 @@
2
2
  import { useTranslations } from 'studiocms:i18n';
3
3
  import { runSDK, SDKCoreJs } from 'studiocms:sdk';
4
4
  import { Effect } from '@withstudiocms/effect';
5
+ import { setDataContext } from '@withstudiocms/effect/astro/data-middleware';
5
6
  import EditFolder from '../../../components/dashboard/content-mgmt/EditFolder.astro';
6
7
  import InnerSidebarElement from '../../../components/dashboard/content-mgmt/InnerSidebarElement.astro';
7
8
  import PageHeader from '../../../components/dashboard/content-mgmt/PageHeader.astro';
@@ -24,12 +25,20 @@ if (!currentFolder) {
24
25
  console.warn(`Folder with ID ${editId} not found.`);
25
26
  return new Response(null, { status: 404 });
26
27
  }
28
+
29
+ setDataContext(Astro, {
30
+ key: 'x-required-role',
31
+ value: 'editor',
32
+ });
33
+ setDataContext(Astro, {
34
+ key: 'x-redirect-url',
35
+ value: Astro.locals.StudioCMS.routeMap.mainLinks.dashboardIndex,
36
+ });
27
37
  ---
28
38
 
29
39
  <Layout
30
40
  title={t('title')}
31
41
  description={t('description')}
32
- requiredPermission='editor'
33
42
  sidebar='double'
34
43
  {lang}
35
44
  {config}
@@ -2,6 +2,7 @@
2
2
  import { getRegistryComponents } from 'studiocms:component-registry/runtime';
3
3
  import { useTranslations } from 'studiocms:i18n';
4
4
  import { runSDK, SDKCoreJs } from 'studiocms:sdk';
5
+ import { setDataContext } from '@withstudiocms/effect/astro/data-middleware';
5
6
  import { Effect } from 'effect';
6
7
  import ComponentRegistryUI from '#frontend/components/shared/ComponentRegistryUI.astro';
7
8
  import BrowserCopyOutput from '#frontend/components/shared/storage-manager/BrowserCopyOutput.astro';
@@ -31,12 +32,20 @@ const [pageData, users, folderList, categories, tags] = await runSDK(
31
32
  SDKCoreJs.GET.tags.getAll(),
32
33
  ])
33
34
  );
35
+
36
+ setDataContext(Astro, {
37
+ key: 'x-required-role',
38
+ value: 'editor',
39
+ });
40
+ setDataContext(Astro, {
41
+ key: 'x-redirect-url',
42
+ value: Astro.locals.StudioCMS.routeMap.mainLinks.dashboardIndex,
43
+ });
34
44
  ---
35
45
 
36
46
  <Layout
37
47
  title={t('title')}
38
48
  description={t('description')}
39
- requiredPermission='editor'
40
49
  sidebar='double'
41
50
  {lang}
42
51
  {config}
@@ -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 InnerSidebarElement from '../../../components/dashboard/content-mgmt/InnerSidebarElement.astro';
4
5
  import PageHeader from '../../../components/dashboard/content-mgmt/PageHeader.astro';
5
6
  import Layout from '../../../layouts/DashboardLayout.astro';
@@ -9,12 +10,20 @@ 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:content-index');
13
+
14
+ setDataContext(Astro, {
15
+ key: 'x-required-role',
16
+ value: 'editor',
17
+ });
18
+ setDataContext(Astro, {
19
+ key: 'x-redirect-url',
20
+ value: Astro.locals.StudioCMS.routeMap.mainLinks.dashboardIndex,
21
+ });
12
22
  ---
13
23
 
14
24
  <Layout
15
25
  title={t('title')}
16
26
  description={t('description')}
17
- requiredPermission='editor'
18
27
  sidebar='double'
19
28
  {lang}
20
29
  {config}
@@ -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 DashboardGrid from '../../components/dashboard/DashboardGrid.astro';
4
5
  import DashboardPageHeader from '../../components/dashboard/DashboardPageHeader.astro';
5
6
  import Layout from '../../layouts/DashboardLayout.astro';
@@ -9,12 +10,20 @@ 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:index');
13
+
14
+ setDataContext(Astro, {
15
+ key: 'x-required-role',
16
+ value: 'editor',
17
+ });
18
+ setDataContext(Astro, {
19
+ key: 'x-redirect-url',
20
+ value: Astro.locals.StudioCMS.routeMap.mainLinks.userProfile,
21
+ });
12
22
  ---
13
23
 
14
24
  <Layout
15
25
  title={t('title')}
16
26
  description={t('description')}
17
- requiredPermission='editor'
18
27
  {lang}
19
28
  {config}
20
29
  {currentUser}