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,359 +0,0 @@
1
- import { apiResponseLogger } from 'studiocms:logger';
2
- import { Notifications } from 'studiocms:notifier';
3
- import plugins from 'studiocms:plugins';
4
- import { apiEndpoints } from 'studiocms:plugins/endpoints';
5
- import { SDKCore } from 'studiocms:sdk';
6
- import type {
7
- CombinedInsertContent,
8
- tsPageContentSelect,
9
- tsPageData,
10
- tsPageDataSelect,
11
- } from 'studiocms:sdk/types';
12
- import {
13
- AllResponse,
14
- createEffectAPIRoutes,
15
- createJsonResponse,
16
- Effect,
17
- genLogger,
18
- OptionsResponse,
19
- readAPIContextJson,
20
- Schema,
21
- } from '@withstudiocms/effect';
22
- import { StudioCMSPageData } from '@withstudiocms/sdk/tables';
23
- import type { PluginAPIRoute } from '#plugins';
24
-
25
- type ApiEndpoints = {
26
- onCreate?: PluginAPIRoute<'onCreate'> | null;
27
- onEdit?: PluginAPIRoute<'onEdit'> | null;
28
- onDelete?: PluginAPIRoute<'onDelete'> | null;
29
- };
30
-
31
- type PageTypeOutput = {
32
- identifier: string;
33
- label: string;
34
- description?: string | undefined;
35
- pageContentComponent?: string | undefined;
36
- apiEndpoint?: string;
37
- apiEndpoints?: ApiEndpoints | undefined;
38
- };
39
-
40
- type UpdatePageData = Partial<tsPageDataSelect>;
41
- type UpdatePageContent = Partial<tsPageContentSelect>;
42
-
43
- const pageTypeOptions = plugins.flatMap(({ pageTypes }) => {
44
- const pageTypeOutput: PageTypeOutput[] = [];
45
-
46
- if (!pageTypes) return pageTypeOutput;
47
-
48
- for (const pageType of pageTypes) {
49
- pageTypeOutput.push({
50
- ...pageType,
51
- apiEndpoints: apiEndpoints.find((endpoint) => endpoint.identifier === pageType.identifier),
52
- });
53
- }
54
-
55
- return pageTypeOutput;
56
- });
57
-
58
- function getPageTypeEndpoints<T extends 'onCreate' | 'onEdit' | 'onDelete'>(pkg: string, type: T) {
59
- const currentPageType = pageTypeOptions.find((pageType) => pageType.identifier === pkg);
60
-
61
- if (!currentPageType) return undefined;
62
-
63
- return currentPageType.apiEndpoints?.[type];
64
- }
65
-
66
- export const { POST, PATCH, DELETE, OPTIONS, ALL } = createEffectAPIRoutes(
67
- {
68
- POST: (ctx) =>
69
- genLogger('studiocms/routes/api/dashboard/content/page.POST')(function* () {
70
- const [sdk, notify] = yield* Effect.all([SDKCore, Notifications]);
71
-
72
- // Get user data
73
- const userData = ctx.locals.StudioCMS.security?.userSessionData;
74
-
75
- // Check if user is logged in
76
- if (!userData?.isLoggedIn) {
77
- return apiResponseLogger(403, 'Unauthorized');
78
- }
79
-
80
- // Check if user has permission
81
- const isAuthorized = ctx.locals.StudioCMS.security?.userPermissionLevel.isEditor;
82
- if (!isAuthorized) {
83
- return apiResponseLogger(403, 'Unauthorized');
84
- }
85
-
86
- const data = yield* readAPIContextJson<UpdatePageData>(ctx);
87
-
88
- const content = {
89
- id: crypto.randomUUID(),
90
- // content is no longer supported during page creation due to current editor setup
91
- // look into options in the future for how we can do this correctly.
92
- // Requires being able to swap in editors which currently does not work.
93
- content: '',
94
- } as UpdatePageContent;
95
-
96
- if (!data.title) {
97
- return apiResponseLogger(400, 'Invalid form data, title is required');
98
- }
99
-
100
- const dataId = crypto.randomUUID();
101
-
102
- // biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
103
- const apiRoute = getPageTypeEndpoints(data.package!, 'onCreate');
104
-
105
- const pageContent: CombinedInsertContent = {
106
- contentLang: 'default',
107
- content: content.content || '',
108
- };
109
-
110
- const {
111
- title,
112
- slug,
113
- description,
114
- categories,
115
- tags,
116
- augments,
117
- contributorIds,
118
- updatedAt: ___updatedAt,
119
- ...rest
120
- } = data as unknown as tsPageData['Insert']['Type'];
121
-
122
- yield* Effect.logInfo('11111');
123
-
124
- const newData = yield* sdk.POST.page({
125
- pageData: {
126
- ...rest,
127
- id: dataId,
128
- title: title,
129
- slug: slug || title.toLowerCase().replace(/\s/g, '-'),
130
- description: description || '',
131
- authorId: userData.user?.id || '',
132
- updatedAt: new Date().toISOString(),
133
- publishedAt: new Date().toISOString(),
134
- categories: JSON.stringify(categories || []),
135
- tags: JSON.stringify(tags || []),
136
- augments: JSON.stringify(augments || []),
137
- contributorIds: JSON.stringify(contributorIds || []),
138
- contentLang: 'default',
139
- },
140
- pageContent: pageContent,
141
- });
142
- yield* Effect.logInfo('22222');
143
-
144
- if (!newData) {
145
- return apiResponseLogger(500, 'Failed to create page');
146
- }
147
-
148
- if (apiRoute) {
149
- yield* Effect.tryPromise(() => apiRoute({ AstroCtx: ctx, pageData: newData }));
150
- }
151
-
152
- yield* Effect.all([sdk.CLEAR.pages, notify.sendEditorNotification('new_page', data.title)]);
153
-
154
- return apiResponseLogger(200, 'Page created successfully');
155
- }).pipe(Notifications.Provide),
156
- PATCH: (ctx) =>
157
- genLogger('studiocms/routes/api/dashboard/content/page.PATCH')(function* () {
158
- const [sdk, notify] = yield* Effect.all([SDKCore, Notifications]);
159
-
160
- // Get user data
161
- const userData = ctx.locals.StudioCMS.security?.userSessionData;
162
-
163
- // Check if user is logged in
164
- if (!userData?.isLoggedIn) {
165
- return apiResponseLogger(403, 'Unauthorized');
166
- }
167
-
168
- // Check if user has permission
169
- const isAuthorized = ctx.locals.StudioCMS.security?.userPermissionLevel.isEditor;
170
- if (!isAuthorized) {
171
- return apiResponseLogger(403, 'Unauthorized');
172
- }
173
-
174
- const combinedData = yield* readAPIContextJson<
175
- UpdatePageData & {
176
- contentId: string;
177
- content: string;
178
- pluginFields: Record<string, FormDataEntryValue | null>;
179
- augments?: string[];
180
- }
181
- >(ctx);
182
-
183
- const { contentId, content: incomingContent, pluginFields, ...data } = combinedData;
184
-
185
- if (!data.id) {
186
- return apiResponseLogger(400, 'Invalid form data, id is required');
187
- }
188
-
189
- if (!contentId) {
190
- return apiResponseLogger(400, 'Invalid form data, contentId is required');
191
- }
192
-
193
- const content = {
194
- id: contentId,
195
- contentId: data.id,
196
- content: incomingContent,
197
- contentLang: 'default',
198
- };
199
-
200
- const currentPageData = yield* sdk.GET.page.byId(data.id);
201
-
202
- if (!currentPageData) {
203
- return apiResponseLogger(404, 'Page not found');
204
- }
205
-
206
- const { authorId, contributorIds, defaultContent } = currentPageData;
207
-
208
- let AuthorId = authorId;
209
-
210
- if (!authorId) {
211
- // biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
212
- AuthorId = userData.user!.id;
213
- }
214
-
215
- const ContributorIds = contributorIds || [];
216
-
217
- // biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
218
- if (!ContributorIds.includes(userData.user!.id)) {
219
- // biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
220
- ContributorIds.push(userData.user!.id);
221
- }
222
-
223
- const newData: tsPageData['Update']['Type'] = {
224
- ...(data as tsPageDataSelect),
225
- authorId: AuthorId,
226
- contributorIds: JSON.stringify(ContributorIds),
227
- updatedAt: new Date().toISOString(),
228
- publishedAt:
229
- currentPageData.draft && data.draft === false
230
- ? new Date().toISOString()
231
- : currentPageData.publishedAt?.toISOString() || new Date().toISOString(),
232
- categories: JSON.stringify(data.categories || []),
233
- tags: JSON.stringify(data.tags || []),
234
- augments: JSON.stringify(data.augments || []),
235
- contentLang: 'default',
236
- };
237
-
238
- const getMetaData = sdk.dbService.withCodec({
239
- encoder: Schema.String,
240
- decoder: StudioCMSPageData.Select,
241
- callbackFn: (query, input) =>
242
- query((db) =>
243
- db
244
- .selectFrom('StudioCMSPageData')
245
- .selectAll()
246
- .where('id', '=', input)
247
- .executeTakeFirstOrThrow()
248
- ),
249
- });
250
-
251
- const startMetaData = yield* getMetaData(data.id);
252
-
253
- // biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
254
- const apiRoute = getPageTypeEndpoints(data.package!, 'onEdit');
255
-
256
- const updatedPage = yield* sdk.UPDATE.page.byId(data.id, {
257
- pageData: newData,
258
- pageContent: content,
259
- });
260
-
261
- if (!updatedPage) {
262
- return apiResponseLogger(500, 'Failed to update page');
263
- }
264
-
265
- const updatedMetaData = yield* getMetaData(data.id);
266
-
267
- const { enableDiffs, diffPerPage = 10 } = ctx.locals.StudioCMS.siteConfig.data;
268
-
269
- if (enableDiffs) {
270
- yield* sdk.diffTracking.insert(
271
- // biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
272
- userData.user!.id,
273
- data.id,
274
- {
275
- content: {
276
- start: defaultContent?.content || '',
277
- end: content.content || '',
278
- },
279
- // biome-ignore lint/style/noNonNullAssertion: this is a valid use case for non-null assertion
280
- metaData: { start: startMetaData!, end: updatedMetaData! },
281
- },
282
- diffPerPage
283
- );
284
- }
285
-
286
- if (apiRoute) {
287
- yield* Effect.tryPromise(() =>
288
- apiRoute({ AstroCtx: ctx, pageData: updatedPage, pluginFields })
289
- );
290
- }
291
-
292
- yield* Effect.all([
293
- sdk.CLEAR.pages,
294
- notify.sendEditorNotification('page_updated', data.title || startMetaData?.title || ''),
295
- ]);
296
-
297
- return apiResponseLogger(200, 'Page updated successfully');
298
- }).pipe(Notifications.Provide),
299
- DELETE: (ctx) =>
300
- genLogger('studiocms/routes/api/dashboard/content/page.DELETE')(function* () {
301
- const [sdk, notify] = yield* Effect.all([SDKCore, Notifications]);
302
-
303
- // Get user data
304
- const userData = ctx.locals.StudioCMS.security?.userSessionData;
305
-
306
- // Check if user is logged in
307
- if (!userData?.isLoggedIn) {
308
- return apiResponseLogger(403, 'Unauthorized');
309
- }
310
-
311
- // Check if user has permission
312
- const isAuthorized = ctx.locals.StudioCMS.security?.userPermissionLevel.isAdmin;
313
- if (!isAuthorized) {
314
- return apiResponseLogger(403, 'Unauthorized');
315
- }
316
-
317
- const { id, slug } = yield* readAPIContextJson<{ id: string; slug?: string }>(ctx);
318
-
319
- const pageToDelete = yield* sdk.GET.page.byId(id);
320
-
321
- if (!pageToDelete) {
322
- return apiResponseLogger(404, 'Page not found');
323
- }
324
- if (pageToDelete.slug !== slug) {
325
- return apiResponseLogger(400, 'Invalid request');
326
- }
327
-
328
- const apiRoute = getPageTypeEndpoints(pageToDelete.package, 'onDelete');
329
-
330
- yield* sdk.DELETE.page(id);
331
-
332
- if (apiRoute) {
333
- yield* Effect.tryPromise(() => apiRoute({ AstroCtx: ctx, pageData: pageToDelete }));
334
- }
335
-
336
- yield* Effect.all([
337
- sdk.CLEAR.pages,
338
- notify.sendEditorNotification('page_deleted', pageToDelete.title),
339
- ]);
340
-
341
- return apiResponseLogger(200, 'Page deleted successfully');
342
- }).pipe(Notifications.Provide),
343
- OPTIONS: () =>
344
- Effect.try(() => OptionsResponse({ allowedMethods: ['POST', 'PATCH', 'DELETE'] })),
345
- ALL: () => Effect.try(() => AllResponse()),
346
- },
347
- {
348
- cors: { methods: ['POST', 'PATCH', 'DELETE', 'OPTIONS'] },
349
- onError: (error) => {
350
- console.error('API Error:', error);
351
- return createJsonResponse(
352
- { error: 'Internal Server Error' },
353
- {
354
- status: 500,
355
- }
356
- );
357
- },
358
- }
359
- );
@@ -1,77 +0,0 @@
1
- import { developerConfig } from 'studiocms:config';
2
- import { apiResponseLogger } from 'studiocms:logger';
3
- import { Notifications } from 'studiocms:notifier';
4
- import { SDKCore } from 'studiocms:sdk';
5
- import {
6
- AllResponse,
7
- createEffectAPIRoutes,
8
- createJsonResponse,
9
- Effect,
10
- genLogger,
11
- OptionsResponse,
12
- readAPIContextJson,
13
- } from '@withstudiocms/effect';
14
-
15
- export const { POST, OPTIONS, ALL } = createEffectAPIRoutes(
16
- {
17
- POST: (ctx) =>
18
- genLogger('studiocms/routes/api/dashboard/create-reset-link.POST')(function* () {
19
- const [notify, sdk] = yield* Effect.all([Notifications, SDKCore]);
20
-
21
- // Check if demo mode is enabled
22
- if (developerConfig.demoMode !== false) {
23
- return apiResponseLogger(403, 'Demo mode is enabled, this action is not allowed.');
24
- }
25
-
26
- // Get user data
27
- const userData = ctx.locals.StudioCMS.security?.userSessionData;
28
-
29
- // Check if user is logged in
30
- if (!userData?.isLoggedIn) {
31
- return apiResponseLogger(403, 'Unauthorized');
32
- }
33
-
34
- // Check if user has permission
35
- const isAuthorized = ctx.locals.StudioCMS.security?.userPermissionLevel.isAdmin;
36
- if (!isAuthorized) {
37
- return apiResponseLogger(403, 'Unauthorized');
38
- }
39
-
40
- const { userId } = yield* readAPIContextJson<{ userId: string }>(ctx);
41
-
42
- if (!userId) {
43
- return apiResponseLogger(400, 'Invalid form data, userId is required');
44
- }
45
-
46
- const token = yield* sdk.resetTokenBucket.new(userId);
47
-
48
- if (!token) {
49
- return apiResponseLogger(500, 'Failed to create reset link');
50
- }
51
-
52
- const user = yield* sdk.GET.users.byId(userId);
53
-
54
- if (!user) {
55
- return apiResponseLogger(404, 'User not found');
56
- }
57
-
58
- yield* notify.sendAdminNotification('user_updated', user.username);
59
-
60
- return createJsonResponse(token);
61
- }).pipe(Notifications.Provide),
62
- OPTIONS: () => Effect.try(() => OptionsResponse({ allowedMethods: ['POST'] })),
63
- ALL: () => Effect.try(() => AllResponse()),
64
- },
65
- {
66
- cors: { methods: ['POST', 'OPTIONS'] },
67
- onError: (error) => {
68
- console.error('API Error:', error);
69
- return createJsonResponse(
70
- { error: 'Internal Server Error' },
71
- {
72
- status: 500,
73
- }
74
- );
75
- },
76
- }
77
- );
@@ -1,231 +0,0 @@
1
- import { User } from 'studiocms:auth/lib';
2
- import { apiResponseLogger } from 'studiocms:logger';
3
- import { Mailer } from 'studiocms:mailer';
4
- import { Notifications } from 'studiocms:notifier';
5
- import { SDKCore } from 'studiocms:sdk';
6
- import templateEngine from 'studiocms:template-engine';
7
- import type { AvailablePermissionRanks } from '@withstudiocms/auth-kit/types';
8
- import {
9
- AllResponse,
10
- appendSearchParamsToUrl,
11
- createEffectAPIRoutes,
12
- createJsonResponse,
13
- Effect,
14
- genLogger,
15
- OptionsResponse,
16
- pipe,
17
- readAPIContextJson,
18
- } from '@withstudiocms/effect';
19
- import type { APIContext } from 'astro';
20
- import { z } from 'astro/zod';
21
-
22
- type JSONData = {
23
- username: string | undefined;
24
- email: string | undefined;
25
- displayname: string | undefined;
26
- rank: AvailablePermissionRanks | undefined;
27
- originalUrl: string;
28
- };
29
-
30
- type Token = {
31
- id: string;
32
- userId: string;
33
- token: string;
34
- };
35
-
36
- const generateResetUrl = (
37
- {
38
- locals: {
39
- StudioCMS: {
40
- routeMap: {
41
- mainLinks: { dashboardIndex },
42
- },
43
- },
44
- },
45
- }: APIContext,
46
- baseUrl: string,
47
- { id, userId, token }: Token
48
- ) => {
49
- const resetURL = new URL(`${dashboardIndex}/password-reset`, baseUrl);
50
- return pipe(
51
- resetURL,
52
- appendSearchParamsToUrl('userid', userId),
53
- appendSearchParamsToUrl('token', token),
54
- appendSearchParamsToUrl('id', id)
55
- );
56
- };
57
-
58
- const noMailerError = (message: string, resetLink: URL) =>
59
- `Failed to send email: ${message}. You can provide the following Reset link to your User: ${resetLink}`;
60
-
61
- export const { POST, OPTIONS, ALL } = createEffectAPIRoutes(
62
- {
63
- POST: (ctx) =>
64
- genLogger('studiocms/routes/api/dashboard/create-user-invite.POST')(function* () {
65
- const [userHelper, mailer, notify, sdk] = yield* Effect.all([
66
- User,
67
- Mailer,
68
- Notifications,
69
- SDKCore,
70
- ]);
71
-
72
- const siteConfig = ctx.locals.StudioCMS.siteConfig.data;
73
-
74
- if (!siteConfig) {
75
- return apiResponseLogger(500, 'Failed to get site config');
76
- }
77
-
78
- // Get user data
79
- const userData = ctx.locals.StudioCMS.security?.userSessionData;
80
-
81
- // Check if user is logged in
82
- if (!userData?.isLoggedIn) {
83
- return apiResponseLogger(403, 'Unauthorized');
84
- }
85
-
86
- // Check if user has permission
87
- const isAuthorized = ctx.locals.StudioCMS.security?.userPermissionLevel.isAdmin;
88
- if (!isAuthorized) {
89
- return apiResponseLogger(403, 'Unauthorized');
90
- }
91
-
92
- const { username, email, displayname, rank, originalUrl } =
93
- yield* readAPIContextJson<JSONData>(ctx);
94
-
95
- // If the username, password, email, or display name is missing, return an error
96
- if (!username) {
97
- return apiResponseLogger(400, 'Missing field: Username is required');
98
- }
99
-
100
- if (!email) {
101
- return apiResponseLogger(400, 'Missing field: Email is required');
102
- }
103
-
104
- if (!displayname) {
105
- return apiResponseLogger(400, 'Missing field: Display name is required');
106
- }
107
-
108
- if (!rank) {
109
- return apiResponseLogger(400, 'Missing field: Rank is required');
110
- }
111
-
112
- const userPerms = ctx.locals.StudioCMS.security?.userPermissionLevel;
113
- if (rank === 'owner' && !userPerms?.isOwner) {
114
- return apiResponseLogger(403, 'Unauthorized');
115
- }
116
-
117
- // If the email is invalid, return an error
118
- const checkEmail = z.coerce
119
- .string()
120
- .email({ message: 'Email address is invalid' })
121
- .safeParse(email);
122
-
123
- if (!checkEmail.success) {
124
- return apiResponseLogger(400, `Invalid email: ${checkEmail.error.message}`);
125
- }
126
-
127
- const [verifyUsernameResponse, { usernameSearch, emailSearch }] = yield* Effect.all([
128
- userHelper.verifyUsernameInput(username),
129
- sdk.AUTH.user.searchUsersForUsernameOrEmail(username, checkEmail.data),
130
- ]);
131
-
132
- if (verifyUsernameResponse !== true) {
133
- return apiResponseLogger(400, verifyUsernameResponse);
134
- }
135
-
136
- if (usernameSearch.length > 0) {
137
- return apiResponseLogger(400, 'Invalid username: Username is already in use');
138
- }
139
-
140
- if (emailSearch.length > 0) {
141
- return apiResponseLogger(400, 'Invalid email: Email is already in use');
142
- }
143
-
144
- // Creates a new user invite
145
- const token = yield* sdk.AUTH.user
146
- .create(
147
- {
148
- username,
149
- email: checkEmail.data,
150
- name: displayname,
151
- createdAt: new Date().toISOString(),
152
- id: crypto.randomUUID(),
153
- avatar: undefined,
154
- emailVerified: false,
155
- notifications: undefined,
156
- password: undefined,
157
- updatedAt: new Date().toISOString(),
158
- url: undefined,
159
- },
160
- rank
161
- )
162
- .pipe(Effect.flatMap((newUser) => sdk.resetTokenBucket.new(newUser.id)));
163
-
164
- if (!token) {
165
- return apiResponseLogger(500, 'Failed to create reset token');
166
- }
167
-
168
- const resetLink = generateResetUrl(ctx, originalUrl, token);
169
-
170
- yield* notify.sendAdminNotification('new_user', username);
171
-
172
- if (siteConfig.enableMailer) {
173
- const checkMailConnection = yield* mailer.verifyMailConnection;
174
-
175
- if (!checkMailConnection) {
176
- return apiResponseLogger(
177
- 500,
178
- noMailerError('Failed to connect to mail server', resetLink)
179
- );
180
- }
181
-
182
- if ('error' in checkMailConnection) {
183
- return apiResponseLogger(
184
- 500,
185
- noMailerError('Failed to connect to mail server', resetLink)
186
- );
187
- }
188
-
189
- const engine = yield* templateEngine;
190
- const { title: siteTitle, description, siteIcon } = siteConfig;
191
-
192
- const userInviteTemplate = yield* engine.render('userInvite', {
193
- site: { title: siteTitle, description, icon: siteIcon ?? undefined },
194
- data: { link: resetLink.toString() },
195
- });
196
-
197
- const mailResponse = yield* mailer.sendMail({
198
- to: checkEmail.data,
199
- subject: `You have been invited to join ${siteConfig.title}!`,
200
- html: userInviteTemplate,
201
- });
202
-
203
- if (!mailResponse) {
204
- return apiResponseLogger(500, noMailerError('Failed to send email', resetLink));
205
- }
206
-
207
- if ('error' in mailResponse) {
208
- return apiResponseLogger(500, noMailerError(mailResponse.error, resetLink));
209
- }
210
-
211
- return apiResponseLogger(200, 'User invite created and email sent');
212
- }
213
-
214
- return apiResponseLogger(200, resetLink.toString());
215
- }).pipe(Mailer.Provide, Notifications.Provide),
216
- OPTIONS: () => Effect.try(() => OptionsResponse({ allowedMethods: ['POST'] })),
217
- ALL: () => Effect.try(() => AllResponse()),
218
- },
219
- {
220
- cors: { methods: ['POST', 'OPTIONS'] },
221
- onError: (error) => {
222
- console.error('API Error:', error);
223
- return createJsonResponse(
224
- { error: 'Internal Server Error' },
225
- {
226
- status: 500,
227
- }
228
- );
229
- },
230
- }
231
- );