studiocms 0.3.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 (263) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/dist/cli/add/index.d.ts +2 -2
  3. package/dist/cli/add/npm-utils.d.ts +6 -6
  4. package/dist/cli/add/tryToInstallPlugins.d.ts +1 -1
  5. package/dist/cli/add/updateStudioCMSConfig.d.ts +1 -1
  6. package/dist/cli/add/validatePlugins.d.ts +1 -1
  7. package/dist/cli/crypto/genJWT/index.d.ts +1 -1
  8. package/dist/cli/crypto/index.d.ts +1 -1
  9. package/dist/cli/init/steps/env.js +12 -2
  10. package/dist/cli/init/steps/next.d.ts +1 -1
  11. package/dist/cli/migrator/index.d.ts +1 -1
  12. package/dist/cli/users/index.d.ts +1 -1
  13. package/dist/cli/users/steps/createUsers.js +3 -3
  14. package/dist/cli/users/steps/next.d.ts +1 -1
  15. package/dist/cli/utils/context.d.ts +1 -1
  16. package/dist/cli/utils/getCliDbClient.d.ts +1 -1
  17. package/dist/cli/utils/intro.d.ts +1 -1
  18. package/dist/cli/utils/loadConfig.d.ts +54 -49
  19. package/dist/cli/utils/loadConfig.js +5 -8
  20. package/dist/cli/utils/user-utils.d.ts +1 -1
  21. package/dist/client/apiClient.d.ts +4923 -0
  22. package/dist/client/apiClient.js +72 -0
  23. package/dist/config.d.ts +1734 -1
  24. package/dist/consts.d.ts +5 -5
  25. package/dist/consts.js +3 -2
  26. package/dist/db/plugins.d.ts +1 -1
  27. package/dist/db/plugins.js +5 -8
  28. package/dist/handlers/frontend/routes.d.ts +4 -18
  29. package/dist/handlers/frontend/routes.js +13 -152
  30. package/dist/handlers/frontend/types.d.ts +1 -1
  31. package/dist/handlers/frontend/utils.js +0 -18
  32. package/dist/handlers/pluginHandler.d.ts +34 -257
  33. package/dist/handlers/pluginHandler.js +92 -46
  34. package/dist/handlers/routeHandler.js +32 -11
  35. package/dist/handlers/setupDbStudio.d.ts +1 -1
  36. package/dist/handlers/storage-manager/core/effectify-astro-context.d.ts +25 -0
  37. package/dist/handlers/storage-manager/core/effectify-astro-context.js +78 -0
  38. package/dist/handlers/storage-manager/no-op.d.ts +2 -2
  39. package/dist/handlers/storage-manager/no-op.js +2 -3
  40. package/dist/index.d.ts +0 -1
  41. package/dist/index.js +9 -5
  42. package/dist/integrations/robots/index.d.ts +2 -2
  43. package/dist/integrations/robots/index.js +1 -3
  44. package/dist/integrations/robots/schema.d.ts +102 -273
  45. package/dist/integrations/robots/schema.js +220 -209
  46. package/dist/plugins/analytics/assets/schemas.d.ts +14 -9
  47. package/dist/plugins/analytics/assets/schemas.js +25 -17
  48. package/dist/plugins/analytics/db-client.d.ts +1 -1
  49. package/dist/plugins/analytics/index.d.ts +823 -3
  50. package/dist/plugins/analytics/index.js +4 -5
  51. package/dist/plugins/analytics/schemas.d.ts +54 -62
  52. package/dist/plugins/analytics/schemas.js +64 -13
  53. package/dist/plugins/analytics/table.d.ts +1 -1
  54. package/dist/plugins.d.ts +0 -1
  55. package/dist/schemas/config/api.d.ts +17 -0
  56. package/dist/schemas/config/api.js +14 -0
  57. package/dist/schemas/config/auth.d.ts +55 -59
  58. package/dist/schemas/config/auth.js +34 -11
  59. package/dist/schemas/config/dashboard.d.ts +43 -79
  60. package/dist/schemas/config/dashboard.js +43 -12
  61. package/dist/schemas/config/db.d.ts +15 -17
  62. package/dist/schemas/config/db.js +13 -5
  63. package/dist/schemas/config/developer.d.ts +33 -45
  64. package/dist/schemas/config/developer.js +22 -5
  65. package/dist/schemas/config/index.d.ts +398 -521
  66. package/dist/schemas/config/index.js +115 -57
  67. package/dist/schemas/config/sdk.d.ts +50 -196
  68. package/dist/schemas/config/sdk.js +61 -73
  69. package/dist/schemas/custom.d.ts +40 -0
  70. package/dist/schemas/custom.js +41 -0
  71. package/dist/schemas/external-schemas.d.ts +171 -0
  72. package/dist/schemas/external-schemas.js +179 -0
  73. package/dist/schemas/index.d.ts +2 -0
  74. package/dist/schemas/index.js +2 -0
  75. package/dist/schemas/plugins/i18n.d.ts +59 -39
  76. package/dist/schemas/plugins/i18n.js +42 -5
  77. package/dist/schemas/plugins/index.d.ts +7126 -10296
  78. package/dist/schemas/plugins/index.js +260 -276
  79. package/dist/schemas/plugins/shared.d.ts +1293 -3718
  80. package/dist/schemas/plugins/shared.js +320 -329
  81. package/dist/test-utils.d.ts +15 -4
  82. package/dist/test-utils.js +27 -11
  83. package/dist/toolbar/db-viewer/db-shared-types.d.ts +6 -6
  84. package/dist/toolbar/db-viewer/viewer.js +20 -21
  85. package/dist/types.d.ts +30 -0
  86. package/dist/utils/effects/smtp.d.ts +1 -1
  87. package/dist/utils/lang-helper.d.ts +10 -2
  88. package/dist/virtual.d.ts +23 -0
  89. package/dist/virtuals/auth/core.d.ts +5 -5
  90. package/dist/virtuals/auth/verify-email.d.ts +6 -6
  91. package/dist/virtuals/components/Generator.astro +2 -2
  92. package/dist/virtuals/components/Renderer.astro +9 -1
  93. package/dist/virtuals/components/renderFn.d.ts +3 -1
  94. package/dist/virtuals/components/renderFn.js +18 -0
  95. package/dist/virtuals/lib/headDefaults.d.ts +4 -2
  96. package/dist/virtuals/lib/headDefaults.js +0 -2
  97. package/dist/virtuals/lib/routeMap.d.ts +0 -12
  98. package/dist/virtuals/lib/routeMap.js +2 -14
  99. package/dist/virtuals/mailer/index.d.ts +3 -3
  100. package/dist/virtuals/notifier/index.d.ts +5 -5
  101. package/dist/virtuals/plugins/dashboard-pages.d.ts +2 -64
  102. package/dist/virtuals/scripts/StorageFileBrowser.d.ts +1 -172
  103. package/dist/virtuals/scripts/StorageFileBrowser.js +216 -119
  104. package/dist/virtuals/template-engine/index.d.ts +4 -4
  105. package/frontend/components/dashboard/configuration/ConfigForm.astro +218 -110
  106. package/frontend/components/dashboard/content-mgmt/ContentSearch.astro +21 -22
  107. package/frontend/components/dashboard/content-mgmt/CreateFolder.astro +66 -54
  108. package/frontend/components/dashboard/content-mgmt/CreatePage.astro +58 -104
  109. package/frontend/components/dashboard/content-mgmt/EditFolder.astro +65 -67
  110. package/frontend/components/dashboard/content-mgmt/EditPage.astro +86 -134
  111. package/frontend/components/dashboard/content-mgmt/InnerSidebarElement.astro +0 -1
  112. package/frontend/components/dashboard/content-mgmt/PageHeader.astro +33 -52
  113. package/frontend/components/dashboard/content-mgmt/PageTypeHandler.astro +2 -2
  114. package/frontend/components/dashboard/profile/APITokens.astro +219 -158
  115. package/frontend/components/dashboard/profile/BasicInfo.astro +165 -106
  116. package/frontend/components/dashboard/profile/Notifications.astro +27 -18
  117. package/frontend/components/dashboard/profile/UpdatePassword.astro +134 -94
  118. package/frontend/components/dashboard/sidebar/VersionCheck.astro +31 -16
  119. package/frontend/components/dashboard/sidebar/VersionCheckChangelog.astro +18 -11
  120. package/frontend/components/dashboard/sidebar-modals/VersionModal.astro +2 -2
  121. package/frontend/components/dashboard/smtp-config/TemplateEditor.astro +14 -14
  122. package/frontend/components/dashboard/taxonomy/InnerSidebarElement.astro +0 -1
  123. package/frontend/components/dashboard/taxonomy/MetaContainer.astro +0 -2
  124. package/frontend/components/dashboard/taxonomy/PageHeader.astro +16 -24
  125. package/frontend/components/dashboard/taxonomy/TaxonomySearch.astro +23 -27
  126. package/frontend/components/dashboard/user-mgmt/InnerSidebarElement.astro +111 -104
  127. package/frontend/components/dashboard/user-mgmt/UserListItem.astro +9 -22
  128. package/frontend/components/dashboard/user-mgmt/UserListItems.astro +18 -0
  129. package/frontend/components/first-time-setup/snippets/{opt2-studiocms.config.diff → studiocms.config.diff} +1 -0
  130. package/frontend/components/shared/Code.astro +1 -4
  131. package/frontend/components/shared/DynamicSettingsRenderer.astro +1 -1
  132. package/frontend/components/shared/SSRUser.astro +2 -4
  133. package/frontend/components/shared/foldertree/FolderTreeNode.astro +0 -6
  134. package/frontend/components/shared/storage-manager/StorageCopyOutput.astro +0 -1
  135. package/frontend/components/shared/taxonomy/TaxonomyTreeNode.astro +0 -6
  136. package/frontend/layouts/DashboardLayout.astro +0 -9
  137. package/frontend/layouts/TaxonomyLayout.astro +0 -1
  138. package/frontend/middleware/index.ts +102 -61
  139. package/frontend/pages/404.astro +0 -1
  140. package/frontend/pages/[dashboard]/[...pluginPage].astro +10 -1
  141. package/frontend/pages/[dashboard]/configuration.astro +10 -1
  142. package/frontend/pages/[dashboard]/content-management/createfolder.astro +10 -1
  143. package/frontend/pages/[dashboard]/content-management/createpage.astro +10 -1
  144. package/frontend/pages/[dashboard]/content-management/diff.astro +39 -14
  145. package/frontend/pages/[dashboard]/content-management/editfolder.astro +10 -1
  146. package/frontend/pages/[dashboard]/content-management/editpage.astro +10 -1
  147. package/frontend/pages/[dashboard]/content-management/index.astro +10 -1
  148. package/frontend/pages/[dashboard]/index.astro +10 -1
  149. package/frontend/pages/[dashboard]/login.astro +86 -25
  150. package/frontend/pages/[dashboard]/password-reset.astro +22 -16
  151. package/frontend/pages/[dashboard]/plugins/[plugin].astro +10 -1
  152. package/frontend/pages/[dashboard]/profile.astro +10 -1
  153. package/frontend/pages/[dashboard]/signup.astro +153 -52
  154. package/frontend/pages/[dashboard]/smtp-configuration.astro +77 -75
  155. package/frontend/pages/[dashboard]/system-management.astro +10 -1
  156. package/frontend/pages/[dashboard]/taxonomy/categories.astro +30 -41
  157. package/frontend/pages/[dashboard]/taxonomy/index.astro +10 -0
  158. package/frontend/pages/[dashboard]/taxonomy/tags.astro +33 -43
  159. package/frontend/pages/[dashboard]/unverified-email.astro +29 -21
  160. package/frontend/pages/[dashboard]/user-management/edit.astro +170 -90
  161. package/frontend/pages/[dashboard]/user-management/index.astro +10 -1
  162. package/frontend/pages/studiocms_api/[...all].ts +106 -0
  163. package/frontend/pages/studiocms_api/_handlers/_utils/auth.ts +26 -0
  164. package/frontend/pages/studiocms_api/_handlers/_utils/changelog.ts +147 -0
  165. package/frontend/pages/studiocms_api/_handlers/_utils/db-studio-driver.ts +46 -0
  166. package/frontend/pages/studiocms_api/_handlers/_utils/parseLogLevel.ts +27 -0
  167. package/frontend/pages/studiocms_api/_handlers/auth/auth.ts +459 -0
  168. package/frontend/pages/studiocms_api/_handlers/auth/index.ts +17 -0
  169. package/frontend/pages/studiocms_api/_handlers/auth/oauth.ts +91 -0
  170. package/frontend/pages/studiocms_api/_handlers/dashboard/_shared.ts +57 -0
  171. package/frontend/pages/studiocms_api/_handlers/dashboard/apiTokens.ts +134 -0
  172. package/frontend/pages/studiocms_api/_handlers/dashboard/config.ts +64 -0
  173. package/frontend/pages/studiocms_api/_handlers/dashboard/content.ts +741 -0
  174. package/frontend/pages/studiocms_api/_handlers/dashboard/create.ts +480 -0
  175. package/frontend/pages/studiocms_api/_handlers/dashboard/emailNotifications.ts +49 -0
  176. package/frontend/pages/studiocms_api/_handlers/dashboard/index.ts +45 -0
  177. package/frontend/pages/studiocms_api/_handlers/dashboard/mailer.ts +136 -0
  178. package/frontend/pages/studiocms_api/_handlers/dashboard/plugins.ts +80 -0
  179. package/frontend/pages/studiocms_api/_handlers/dashboard/profile.ts +275 -0
  180. package/frontend/pages/studiocms_api/_handlers/dashboard/resetPassword.ts +140 -0
  181. package/frontend/pages/studiocms_api/_handlers/dashboard/search.ts +63 -0
  182. package/frontend/pages/studiocms_api/_handlers/dashboard/taxonomy.ts +285 -0
  183. package/frontend/pages/studiocms_api/_handlers/dashboard/templates.ts +75 -0
  184. package/frontend/pages/studiocms_api/_handlers/dashboard/users.ts +312 -0
  185. package/frontend/pages/studiocms_api/_handlers/dashboard/verifyEndpoints.ts +307 -0
  186. package/frontend/pages/studiocms_api/_handlers/integration/dbStudio.ts +98 -0
  187. package/frontend/pages/studiocms_api/_handlers/integration/index.ts +17 -0
  188. package/frontend/pages/studiocms_api/_handlers/integration/storageManager.ts +107 -0
  189. package/frontend/pages/studiocms_api/_handlers/rest-api/index.ts +8 -0
  190. package/frontend/pages/studiocms_api/_handlers/rest-api/v1/_shared.ts +41 -0
  191. package/frontend/pages/studiocms_api/_handlers/rest-api/v1/index.ts +17 -0
  192. package/frontend/pages/studiocms_api/_handlers/rest-api/v1/public.ts +195 -0
  193. package/frontend/pages/studiocms_api/_handlers/rest-api/v1/secure.ts +1726 -0
  194. package/frontend/pages/studiocms_api/_handlers/sdk.ts +129 -0
  195. package/frontend/pages/studiocms_api/_middleware/astroLocals.ts +36 -0
  196. package/frontend/pages/studiocms_api/_middleware/restApi.ts +56 -0
  197. package/frontend/pages/studiocms_api/integrations/[...all].ts +8 -0
  198. package/frontend/scripts/formdata.ts +219 -0
  199. package/frontend/setup-pages/3-done.astro +4 -20
  200. package/frontend/setup-pages/studiocms_api/dashboard/step-2.ts +3 -6
  201. package/frontend/styles/dashboard-base.css +0 -1
  202. package/frontend/web-vitals/endpoint.ts +2 -1
  203. package/package.json +34 -29
  204. package/dist/global.d.ts +0 -9
  205. package/frontend/components/dashboard/LoginChecker.astro +0 -68
  206. package/frontend/components/dashboard/user-mgmt/RankCheck.astro +0 -57
  207. package/frontend/components/first-time-setup/snippets/opt1-astro.config.diff +0 -14
  208. package/frontend/components/first-time-setup/snippets/opt2-astro.config.diff +0 -9
  209. package/frontend/middleware/_authmap.ts +0 -63
  210. package/frontend/pages/studiocms_api/auth/[path].ts +0 -384
  211. package/frontend/pages/studiocms_api/auth/[provider]/[...id].ts +0 -64
  212. package/frontend/pages/studiocms_api/auth/[provider]/_effects/index.ts +0 -101
  213. package/frontend/pages/studiocms_api/auth/_shared.ts +0 -52
  214. package/frontend/pages/studiocms_api/dashboard/api-tokens.ts +0 -115
  215. package/frontend/pages/studiocms_api/dashboard/config.ts +0 -74
  216. package/frontend/pages/studiocms_api/dashboard/content/diff.ts +0 -73
  217. package/frontend/pages/studiocms_api/dashboard/content/folder.ts +0 -220
  218. package/frontend/pages/studiocms_api/dashboard/content/page.ts +0 -359
  219. package/frontend/pages/studiocms_api/dashboard/create-reset-link.ts +0 -77
  220. package/frontend/pages/studiocms_api/dashboard/create-user-invite.ts +0 -231
  221. package/frontend/pages/studiocms_api/dashboard/create-user.ts +0 -186
  222. package/frontend/pages/studiocms_api/dashboard/email-notification-settings-site.ts +0 -74
  223. package/frontend/pages/studiocms_api/dashboard/mailer/check-email.ts +0 -75
  224. package/frontend/pages/studiocms_api/dashboard/mailer/config.ts +0 -136
  225. package/frontend/pages/studiocms_api/dashboard/plugins/[plugin].ts +0 -80
  226. package/frontend/pages/studiocms_api/dashboard/profile.ts +0 -245
  227. package/frontend/pages/studiocms_api/dashboard/resend-verify-email.ts +0 -77
  228. package/frontend/pages/studiocms_api/dashboard/reset-password.ts +0 -124
  229. package/frontend/pages/studiocms_api/dashboard/search-list.ts +0 -59
  230. package/frontend/pages/studiocms_api/dashboard/taxonomy-search.ts +0 -47
  231. package/frontend/pages/studiocms_api/dashboard/taxonomy.ts +0 -230
  232. package/frontend/pages/studiocms_api/dashboard/templates.ts +0 -74
  233. package/frontend/pages/studiocms_api/dashboard/update-user-notifications.ts +0 -86
  234. package/frontend/pages/studiocms_api/dashboard/users.ts +0 -236
  235. package/frontend/pages/studiocms_api/dashboard/verify-email.ts +0 -83
  236. package/frontend/pages/studiocms_api/dashboard/verify-session.ts +0 -187
  237. package/frontend/pages/studiocms_api/integrations/[type]/[...id].ts +0 -15
  238. package/frontend/pages/studiocms_api/integrations/[type]/_routes/db-studio.ts +0 -173
  239. package/frontend/pages/studiocms_api/integrations/[type]/_routes/storage.ts +0 -88
  240. package/frontend/pages/studiocms_api/partials/editor.astro +0 -74
  241. package/frontend/pages/studiocms_api/partials/render.astro +0 -39
  242. package/frontend/pages/studiocms_api/partials/user-list-items.astro +0 -43
  243. package/frontend/pages/studiocms_api/rest/utils/auth-token.ts +0 -59
  244. package/frontend/pages/studiocms_api/rest/v1/[type]/[...id].ts +0 -23
  245. package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/categories.ts +0 -267
  246. package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/folders.ts +0 -283
  247. package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/pages.ts +0 -505
  248. package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/settings.ts +0 -100
  249. package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/tags.ts +0 -229
  250. package/frontend/pages/studiocms_api/rest/v1/[type]/_routes/users.ts +0 -553
  251. package/frontend/pages/studiocms_api/rest/v1/public/[type]/[...id].ts +0 -19
  252. package/frontend/pages/studiocms_api/rest/v1/public/[type]/_routes/categories.ts +0 -74
  253. package/frontend/pages/studiocms_api/rest/v1/public/[type]/_routes/folders.ts +0 -85
  254. package/frontend/pages/studiocms_api/rest/v1/public/[type]/_routes/pages.ts +0 -103
  255. package/frontend/pages/studiocms_api/rest/v1/public/[type]/_routes/tags.ts +0 -67
  256. package/frontend/pages/studiocms_api/sdk/[...path].ts +0 -97
  257. package/frontend/pages/studiocms_api/sdk/utils/changelog.ts +0 -119
  258. package/frontend/scripts/auth/formListener.ts +0 -81
  259. package/frontend/scripts/formdata-utils.ts +0 -116
  260. package/frontend/utils/build-partial-schema.ts +0 -46
  261. package/frontend/utils/errors.ts +0 -6
  262. package/frontend/utils/param-extractor.ts +0 -83
  263. package/frontend/utils/rest-router.ts +0 -444
@@ -1,505 +0,0 @@
1
- import { apiResponseLogger } from 'studiocms:logger';
2
- import { Notifications } from 'studiocms:notifier';
3
- import { SDKCore } from 'studiocms:sdk';
4
- import type { tsPageContentSelect, tsPageData, tsPageDataSelect } from 'studiocms:sdk/types';
5
- import {
6
- AllResponse,
7
- createEffectAPIRoutes,
8
- createJsonResponse,
9
- Effect,
10
- genLogger,
11
- OptionsResponse,
12
- readAPIContextJson,
13
- Schema,
14
- } from '@withstudiocms/effect';
15
- import { StudioCMSPageData } from '@withstudiocms/sdk/tables';
16
- import {
17
- type EndpointRoute,
18
- idOrPathRouter,
19
- type SubPathRouter,
20
- } from '../../../../../../utils/rest-router.js';
21
- import { verifyAuthTokenFromHeader } from '../../../utils/auth-token.js';
22
-
23
- type UpdatePageData = Partial<tsPageDataSelect>;
24
- type UpdatePageContent = Partial<tsPageContentSelect>;
25
-
26
- interface UpdatePageJson {
27
- pageId: string;
28
- data?: UpdatePageData;
29
- content?: UpdatePageContent;
30
- }
31
-
32
- interface CreatePageJson {
33
- data?: tsPageDataSelect;
34
- content?: tsPageContentSelect;
35
- }
36
-
37
- const subPathRouter: SubPathRouter = {
38
- history: (id: string, _params?: Record<string, string>) =>
39
- createEffectAPIRoutes(
40
- {
41
- GET: (ctx) =>
42
- genLogger('studioCMS:rest:v1:public:pages:[id]:history:GET')(function* () {
43
- const [sdk, user] = yield* Effect.all([SDKCore, verifyAuthTokenFromHeader(ctx)]);
44
-
45
- if (user instanceof Response) {
46
- return user;
47
- }
48
-
49
- const { rank } = user;
50
-
51
- if (rank !== 'owner' && rank !== 'admin' && rank !== 'editor') {
52
- return apiResponseLogger(401, 'Unauthorized');
53
- }
54
-
55
- const page = yield* sdk.GET.page.byId(id);
56
-
57
- if (!page) {
58
- return apiResponseLogger(404, 'Page not found');
59
- }
60
-
61
- const searchParams = ctx.url.searchParams;
62
-
63
- const limitParam = searchParams.get('limit');
64
- const parsedLimit = limitParam ? Number.parseInt(limitParam, 10) : undefined;
65
- const limit =
66
- typeof parsedLimit === 'number' && Number.isFinite(parsedLimit) && parsedLimit > 0
67
- ? Math.min(parsedLimit, 100) // clamp to protect backend
68
- : undefined;
69
-
70
- const diffs =
71
- limit !== undefined
72
- ? yield* sdk.diffTracking.get.byPageId.latest(id, limit)
73
- : yield* sdk.diffTracking.get.byPageId.all(id);
74
-
75
- return createJsonResponse(diffs);
76
- }),
77
- OPTIONS: () => Effect.try(() => OptionsResponse({ allowedMethods: ['GET'] })),
78
- ALL: () => Effect.try(() => AllResponse()),
79
- },
80
- {
81
- cors: { methods: ['GET', 'OPTIONS'] },
82
- onError: (error) => {
83
- console.error('API Error:', error);
84
- return createJsonResponse({ error: 'Internal Server Error' }, { status: 500 });
85
- },
86
- }
87
- ),
88
- 'history/[diffId]': (id: string, params?: Record<string, string>) =>
89
- createEffectAPIRoutes(
90
- {
91
- GET: (ctx) =>
92
- genLogger('studioCMS:rest:v1:pages:[id]:history:[diffid]:GET')(function* () {
93
- const sdk = yield* SDKCore;
94
-
95
- const user = yield* verifyAuthTokenFromHeader(ctx);
96
-
97
- if (user instanceof Response) {
98
- return user;
99
- }
100
-
101
- const { rank } = user;
102
-
103
- if (rank !== 'owner' && rank !== 'admin' && rank !== 'editor') {
104
- return apiResponseLogger(401, 'Unauthorized');
105
- }
106
-
107
- const diffId = params?.diffId;
108
-
109
- if (!id) {
110
- return apiResponseLogger(400, 'Invalid page ID');
111
- }
112
-
113
- if (!diffId) {
114
- return apiResponseLogger(400, 'Invalid diff ID');
115
- }
116
-
117
- const diff = yield* sdk.diffTracking.get.single(diffId);
118
-
119
- if (!diff) {
120
- return apiResponseLogger(404, 'Diff not found');
121
- }
122
-
123
- if (diff.pageId !== id) {
124
- return apiResponseLogger(404, 'Diff not found');
125
- }
126
-
127
- return createJsonResponse(diff);
128
- }),
129
- OPTIONS: () => Effect.try(() => OptionsResponse({ allowedMethods: ['GET'] })),
130
- ALL: () => Effect.try(() => AllResponse()),
131
- },
132
- {
133
- cors: { methods: ['GET', 'OPTIONS'] },
134
- onError: (error) => {
135
- console.error('API Error:', error);
136
- return createJsonResponse({ error: 'Internal Server Error' }, { status: 500 });
137
- },
138
- }
139
- ),
140
- };
141
-
142
- const pageIdRouter = (id: string) =>
143
- createEffectAPIRoutes(
144
- {
145
- GET: (ctx) =>
146
- genLogger('studioCMS:rest:v1:pages:[id]:GET')(function* () {
147
- const [sdk, user] = yield* Effect.all([SDKCore, verifyAuthTokenFromHeader(ctx)]);
148
-
149
- if (user instanceof Response) {
150
- return user;
151
- }
152
-
153
- const { rank } = user;
154
-
155
- if (rank !== 'owner' && rank !== 'admin' && rank !== 'editor') {
156
- return apiResponseLogger(401, 'Unauthorized');
157
- }
158
-
159
- const page = yield* sdk.GET.page.byId(id);
160
-
161
- if (!page) {
162
- return apiResponseLogger(404, 'Page not found');
163
- }
164
-
165
- return createJsonResponse(page);
166
- }),
167
- PATCH: (ctx) =>
168
- genLogger('studioCMS:rest:v1:pages:[id]:PATCH')(function* () {
169
- const [sdk, user, notifier] = yield* Effect.all([
170
- SDKCore,
171
- verifyAuthTokenFromHeader(ctx),
172
- Notifications,
173
- ]);
174
-
175
- if (user instanceof Response) {
176
- return user;
177
- }
178
-
179
- const { rank, userId } = user;
180
-
181
- if (rank !== 'owner' && rank !== 'admin' && rank !== 'editor') {
182
- return apiResponseLogger(401, 'Unauthorized');
183
- }
184
-
185
- const jsonData = yield* readAPIContextJson<UpdatePageJson>(ctx);
186
-
187
- const { data, content } = jsonData;
188
-
189
- if (!data) {
190
- return apiResponseLogger(400, 'Invalid form data, data is required');
191
- }
192
-
193
- if (!content) {
194
- return apiResponseLogger(400, 'Invalid form data, content is required');
195
- }
196
-
197
- if (!data.id) {
198
- return apiResponseLogger(400, 'Invalid form data, id is required');
199
- }
200
-
201
- if (!content.id) {
202
- return apiResponseLogger(400, 'Invalid form data, id is required');
203
- }
204
- if (data.id !== id) {
205
- return apiResponseLogger(400, 'Payload id does not match path id');
206
- }
207
-
208
- const currentPageData = yield* sdk.GET.page.byId(id);
209
-
210
- if (!currentPageData) {
211
- return apiResponseLogger(404, 'Page not found');
212
- }
213
-
214
- const { authorId, contributorIds, defaultContent } = currentPageData;
215
-
216
- let AuthorId = authorId;
217
-
218
- if (!authorId) {
219
- AuthorId = userId;
220
- }
221
-
222
- const ContributorIds = contributorIds || [];
223
-
224
- if (!ContributorIds.includes(userId)) {
225
- ContributorIds.push(userId);
226
- }
227
-
228
- const newData: tsPageData['Insert']['Type'] = {
229
- ...(data as tsPageDataSelect),
230
- authorId: AuthorId,
231
- contributorIds: JSON.stringify(ContributorIds),
232
- updatedAt: new Date().toISOString(),
233
- publishedAt:
234
- currentPageData.draft && data.draft === false
235
- ? new Date().toISOString()
236
- : currentPageData.publishedAt?.toISOString() || new Date().toISOString(),
237
- categories: JSON.stringify(data.categories || []),
238
- tags: JSON.stringify(data.tags || []),
239
- augments: JSON.stringify(data.augments || []),
240
- };
241
-
242
- const getMetaData = sdk.dbService.withCodec({
243
- encoder: Schema.String,
244
- decoder: StudioCMSPageData.Select,
245
- callbackFn: (query, input) =>
246
- query((db) =>
247
- db
248
- .selectFrom('StudioCMSPageData')
249
- .selectAll()
250
- .where('id', '=', input)
251
- .executeTakeFirstOrThrow()
252
- ),
253
- });
254
-
255
- const startMetaData = yield* getMetaData(data.id);
256
-
257
- yield* sdk.UPDATE.page.byId(data.id, {
258
- pageData: newData,
259
- pageContent: content as tsPageContentSelect,
260
- });
261
-
262
- const updatedMetaData = yield* getMetaData(data.id);
263
-
264
- const siteConfig = yield* sdk.GET.siteConfig();
265
-
266
- if (!siteConfig) {
267
- return apiResponseLogger(500, 'Site configuration not found');
268
- }
269
-
270
- const { enableDiffs, diffPerPage = 10 } = siteConfig.data;
271
-
272
- if (enableDiffs) {
273
- yield* sdk.diffTracking.insert(
274
- userId,
275
- data.id,
276
- {
277
- content: {
278
- start: defaultContent?.content || '',
279
- end: content.content || '',
280
- },
281
- // biome-ignore lint/style/noNonNullAssertion: This is a valid use case for non-null assertion
282
- metaData: { start: startMetaData!, end: updatedMetaData! },
283
- },
284
- diffPerPage
285
- );
286
- }
287
-
288
- yield* sdk.CLEAR.page.byId(id);
289
-
290
- // biome-ignore lint/style/noNonNullAssertion: This is a valid use case for non-null assertion
291
- yield* notifier.sendEditorNotification('page_updated', updatedMetaData!.title);
292
-
293
- return apiResponseLogger(200, 'Page updated successfully');
294
- }).pipe(Notifications.Provide),
295
- DELETE: (ctx) =>
296
- genLogger('studioCMS:rest:v1:pages:[id]:DELETE')(function* () {
297
- const [sdk, user, notifier] = yield* Effect.all([
298
- SDKCore,
299
- verifyAuthTokenFromHeader(ctx),
300
- Notifications,
301
- ]);
302
-
303
- if (user instanceof Response) {
304
- return user;
305
- }
306
-
307
- const { rank } = user;
308
-
309
- if (rank !== 'owner' && rank !== 'admin') {
310
- return apiResponseLogger(401, 'Unauthorized');
311
- }
312
-
313
- const jsonData = yield* readAPIContextJson<{ slug: string }>(ctx);
314
-
315
- const { slug } = jsonData;
316
-
317
- if (!slug) {
318
- return apiResponseLogger(400, 'Invalid request');
319
- }
320
-
321
- const page = yield* sdk.GET.page.byId(id);
322
-
323
- if (!page) {
324
- return apiResponseLogger(404, 'Page not found');
325
- }
326
-
327
- yield* sdk.DELETE.page(id);
328
- yield* sdk.CLEAR.page.byId(id);
329
-
330
- yield* notifier.sendEditorNotification('page_deleted', page.title);
331
-
332
- return apiResponseLogger(200, 'Page deleted successfully');
333
- }).pipe(Notifications.Provide),
334
- OPTIONS: () =>
335
- Effect.try(() => OptionsResponse({ allowedMethods: ['GET', 'PATCH', 'DELETE'] })),
336
- ALL: () => Effect.try(() => AllResponse()),
337
- },
338
- {
339
- cors: { methods: ['GET', 'PATCH', 'DELETE', 'OPTIONS'] },
340
- onError: (error) => {
341
- console.error('API Error:', error);
342
- return createJsonResponse(
343
- { error: 'Internal Server Error' },
344
- {
345
- status: 500,
346
- }
347
- );
348
- },
349
- }
350
- );
351
-
352
- export const pagesRouter: EndpointRoute = {
353
- __idType: 'string',
354
- __index: createEffectAPIRoutes(
355
- {
356
- GET: (ctx) =>
357
- genLogger('studioCMS:rest:v1:public:pages:GET')(function* () {
358
- const [sdk, user] = yield* Effect.all([SDKCore, verifyAuthTokenFromHeader(ctx)]);
359
-
360
- if (user instanceof Response) {
361
- return user;
362
- }
363
-
364
- const { rank } = user;
365
-
366
- if (rank !== 'owner' && rank !== 'admin' && rank !== 'editor') {
367
- return apiResponseLogger(401, 'Unauthorized');
368
- }
369
-
370
- const pages = yield* sdk.GET.pages(true);
371
-
372
- const searchParams = ctx.url.searchParams;
373
-
374
- const titleFilter = searchParams.get('title');
375
- const slugFilter = searchParams.get('slug');
376
- const authorFilter = searchParams.get('author');
377
- const draftFilter = searchParams.get('draft') === 'true';
378
- const publishedFilter = searchParams.get('published') === 'true';
379
- const parentFolderFilter = searchParams.get('parentFolder');
380
-
381
- let filteredPages = pages;
382
-
383
- if (titleFilter) {
384
- filteredPages = filteredPages.filter((page) => page.title.includes(titleFilter));
385
- }
386
-
387
- if (slugFilter) {
388
- filteredPages = filteredPages.filter((page) => page.slug.includes(slugFilter));
389
- }
390
-
391
- if (authorFilter) {
392
- filteredPages = filteredPages.filter((page) => page.authorId === authorFilter);
393
- }
394
-
395
- if (draftFilter) {
396
- filteredPages = filteredPages.filter((page) => page.draft === draftFilter);
397
- }
398
-
399
- if (publishedFilter) {
400
- filteredPages = filteredPages.filter((page) => !page.draft);
401
- }
402
-
403
- if (parentFolderFilter) {
404
- filteredPages = filteredPages.filter(
405
- (page) => page.parentFolder === parentFolderFilter
406
- );
407
- }
408
-
409
- return createJsonResponse(filteredPages);
410
- }),
411
- POST: (ctx) =>
412
- genLogger('studioCMS:rest:v1:public:pages:POST')(function* () {
413
- const [sdk, user, notifier] = yield* Effect.all([
414
- SDKCore,
415
- verifyAuthTokenFromHeader(ctx),
416
- Notifications,
417
- ]);
418
-
419
- if (user instanceof Response) {
420
- return user;
421
- }
422
-
423
- const { rank, userId } = user;
424
-
425
- if (rank !== 'owner' && rank !== 'admin' && rank !== 'editor') {
426
- return apiResponseLogger(401, 'Unauthorized');
427
- }
428
-
429
- const jsonData = yield* readAPIContextJson<CreatePageJson>(ctx);
430
-
431
- const { data, content } = jsonData;
432
-
433
- if (!data) {
434
- return apiResponseLogger(400, 'Invalid form data, data is required');
435
- }
436
-
437
- if (!content) {
438
- return apiResponseLogger(400, 'Invalid form data, content is required');
439
- }
440
-
441
- if (!data.title) {
442
- return apiResponseLogger(400, 'Invalid form data, title is required');
443
- }
444
-
445
- const dataId = crypto.randomUUID();
446
-
447
- const {
448
- title,
449
- slug,
450
- description,
451
- categories,
452
- tags,
453
- contributorIds,
454
- augments,
455
- id: ___id,
456
- authorId: __authorId,
457
- updatedAt: __updatedAt,
458
- publishedAt: __publishedAt,
459
- ...restPageData
460
- } = data;
461
-
462
- const { id: ____id, ...contentData } = content;
463
-
464
- yield* sdk.POST.databaseEntry.pages(
465
- {
466
- id: dataId,
467
- title,
468
- slug:
469
- slug ||
470
- title
471
- .toLowerCase()
472
- .replace(/[^a-z0-9\s-]/g, '') // Remove special characters
473
- .replace(/\s+/g, '-') // Replace spaces with hyphens
474
- .replace(/-+/g, '-') // Replace multiple hyphens with single hyphen
475
- .replace(/^-|-$/g, ''), // Remove leading/trailing hyphens '-'),
476
- description: description || '',
477
- authorId: userId,
478
- updatedAt: new Date().toISOString(),
479
- publishedAt: new Date().toISOString(),
480
- categories: JSON.stringify(categories || []),
481
- tags: JSON.stringify(tags || []),
482
- contributorIds: JSON.stringify(contributorIds || []),
483
- augments: JSON.stringify(augments || []),
484
- ...restPageData,
485
- },
486
- { ...contentData }
487
- );
488
-
489
- yield* notifier.sendEditorNotification('new_page', data.title);
490
-
491
- return apiResponseLogger(200, `Page created successfully with id: ${dataId}`);
492
- }).pipe(Notifications.Provide),
493
- OPTIONS: () => Effect.try(() => OptionsResponse({ allowedMethods: ['GET', 'POST'] })),
494
- ALL: () => Effect.try(() => AllResponse()),
495
- },
496
- {
497
- cors: { methods: ['GET', 'POST', 'OPTIONS'] },
498
- onError: (error) => {
499
- console.error('API Error:', error);
500
- return createJsonResponse({ error: 'Something went wrong' }, { status: 500 });
501
- },
502
- }
503
- ),
504
- id: (id: string) => idOrPathRouter(id, pageIdRouter, subPathRouter),
505
- };
@@ -1,100 +0,0 @@
1
- import { apiResponseLogger } from 'studiocms:logger';
2
- import { SDKCore } from 'studiocms:sdk';
3
- import {
4
- AllResponse,
5
- createEffectAPIRoutes,
6
- createJsonResponse,
7
- Effect,
8
- genLogger,
9
- OptionsResponse,
10
- readAPIContextJson,
11
- } from '@withstudiocms/effect';
12
- import type { EndpointRoute } from './../../../../../../utils/rest-router.js';
13
- import { verifyAuthTokenFromHeader } from '../../../utils/auth-token.js';
14
-
15
- export const settingsRouter: EndpointRoute = {
16
- __idType: 'string',
17
- __index: createEffectAPIRoutes(
18
- {
19
- GET: (ctx) =>
20
- genLogger('studioCMS:rest:v1:settings:GET')(function* () {
21
- const [sdk, user] = yield* Effect.all([SDKCore, verifyAuthTokenFromHeader(ctx)]);
22
-
23
- if (user instanceof Response) {
24
- return user;
25
- }
26
-
27
- const { rank } = user;
28
-
29
- if (rank !== 'owner') {
30
- return apiResponseLogger(401, 'Unauthorized');
31
- }
32
-
33
- const siteConfig = yield* sdk.GET.siteConfig();
34
-
35
- return createJsonResponse(siteConfig);
36
- }),
37
- PATCH: (ctx) =>
38
- genLogger('studioCMS:rest:v1:settings:PATCH')(function* () {
39
- const [sdk, user] = yield* Effect.all([SDKCore, verifyAuthTokenFromHeader(ctx)]);
40
-
41
- if (user instanceof Response) {
42
- return user;
43
- }
44
-
45
- const { rank } = user;
46
-
47
- if (rank !== 'owner') {
48
- return apiResponseLogger(401, 'Unauthorized');
49
- }
50
-
51
- const siteConfig = yield* readAPIContextJson<{
52
- title: string;
53
- description: string;
54
- loginPageBackground: string;
55
- loginPageCustomImage?: string;
56
- }>(ctx);
57
-
58
- if (typeof siteConfig.title !== 'string' || siteConfig.title.trim() === '') {
59
- return apiResponseLogger(400, 'Invalid form data, title is required');
60
- }
61
-
62
- if (typeof siteConfig.description !== 'string' || siteConfig.description.trim() === '') {
63
- return apiResponseLogger(400, 'Invalid form data, description is required');
64
- }
65
-
66
- if (
67
- typeof siteConfig.loginPageBackground !== 'string' ||
68
- siteConfig.loginPageBackground.trim() === ''
69
- ) {
70
- return apiResponseLogger(400, 'Invalid form data, loginPageBackground is required');
71
- }
72
-
73
- if (
74
- siteConfig.loginPageBackground === 'custom' &&
75
- (typeof siteConfig.loginPageCustomImage !== 'string' ||
76
- siteConfig.loginPageCustomImage.trim() === '')
77
- ) {
78
- return apiResponseLogger(400, 'Invalid form data, loginPageCustomImage is required');
79
- }
80
-
81
- yield* sdk.UPDATE.siteConfig(siteConfig);
82
-
83
- return apiResponseLogger(200, 'Site config updated');
84
- }),
85
- OPTIONS: () => Effect.try(() => OptionsResponse({ allowedMethods: ['GET', 'PATCH'] })),
86
- ALL: () => Effect.try(() => AllResponse()),
87
- },
88
- {
89
- cors: { methods: ['GET', 'PATCH', 'OPTIONS'] },
90
- onError: (error) => {
91
- console.error('API Error:', error);
92
- if (error instanceof SyntaxError) {
93
- // Likely invalid JSON in request body
94
- return createJsonResponse({ error: 'Invalid JSON' }, { status: 400 });
95
- }
96
- return createJsonResponse({ error: 'Something went wrong' }, { status: 500 });
97
- },
98
- }
99
- ),
100
- };