@btst/plugin-cms 0.0.0-stage → 1.0.0-beta.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 (204) hide show
  1. package/LICENSE.md +17 -0
  2. package/dist/api/getters.cjs +328 -0
  3. package/dist/api/getters.mjs +314 -0
  4. package/dist/api/index.cjs +29 -0
  5. package/dist/api/index.d.cts +209 -0
  6. package/dist/api/index.d.mts +209 -0
  7. package/dist/api/index.d.ts +209 -0
  8. package/dist/api/index.mjs +7 -0
  9. package/dist/api/lifecycle-migrations.cjs +13 -0
  10. package/dist/api/lifecycle-migrations.mjs +11 -0
  11. package/dist/api/mutations.cjs +59 -0
  12. package/dist/api/mutations.mjs +57 -0
  13. package/dist/api/operations.cjs +1769 -0
  14. package/dist/api/operations.mjs +1762 -0
  15. package/dist/api/plugin.cjs +337 -0
  16. package/dist/api/plugin.mjs +331 -0
  17. package/dist/api/query-key-defs.cjs +44 -0
  18. package/dist/api/query-key-defs.mjs +39 -0
  19. package/dist/api/relations.cjs +76 -0
  20. package/dist/api/relations.mjs +70 -0
  21. package/dist/client/components/forms/content-form.cjs +286 -0
  22. package/dist/client/components/forms/content-form.mjs +284 -0
  23. package/dist/client/components/forms/file-upload.cjs +160 -0
  24. package/dist/client/components/forms/file-upload.mjs +158 -0
  25. package/dist/client/components/forms/relation-field.cjs +237 -0
  26. package/dist/client/components/forms/relation-field.mjs +235 -0
  27. package/dist/client/components/index.cjs +14 -0
  28. package/dist/client/components/index.d.cts +20 -0
  29. package/dist/client/components/index.d.mts +20 -0
  30. package/dist/client/components/index.d.ts +20 -0
  31. package/dist/client/components/index.mjs +10 -0
  32. package/dist/client/components/inverse-relations-panel.cjs +272 -0
  33. package/dist/client/components/inverse-relations-panel.mjs +270 -0
  34. package/dist/client/components/loading/dashboard-skeleton.cjs +18 -0
  35. package/dist/client/components/loading/dashboard-skeleton.mjs +16 -0
  36. package/dist/client/components/loading/editor-skeleton.cjs +32 -0
  37. package/dist/client/components/loading/editor-skeleton.mjs +30 -0
  38. package/dist/client/components/loading/list-skeleton.cjs +32 -0
  39. package/dist/client/components/loading/list-skeleton.mjs +30 -0
  40. package/dist/client/components/pages/404-page.cjs +26 -0
  41. package/dist/client/components/pages/404-page.mjs +24 -0
  42. package/dist/client/components/pages/content-editor-page.cjs +84 -0
  43. package/dist/client/components/pages/content-editor-page.internal.cjs +170 -0
  44. package/dist/client/components/pages/content-editor-page.internal.mjs +168 -0
  45. package/dist/client/components/pages/content-editor-page.mjs +82 -0
  46. package/dist/client/components/pages/content-list-page.cjs +49 -0
  47. package/dist/client/components/pages/content-list-page.internal.cjs +334 -0
  48. package/dist/client/components/pages/content-list-page.internal.mjs +332 -0
  49. package/dist/client/components/pages/content-list-page.mjs +47 -0
  50. package/dist/client/components/pages/dashboard-page.cjs +42 -0
  51. package/dist/client/components/pages/dashboard-page.internal.cjs +102 -0
  52. package/dist/client/components/pages/dashboard-page.internal.mjs +100 -0
  53. package/dist/client/components/pages/dashboard-page.mjs +40 -0
  54. package/dist/client/components/shared/default-error.cjs +17 -0
  55. package/dist/client/components/shared/default-error.mjs +15 -0
  56. package/dist/client/components/shared/empty-state.cjs +16 -0
  57. package/dist/client/components/shared/empty-state.mjs +14 -0
  58. package/dist/client/components/shared/page-wrapper.cjs +29 -0
  59. package/dist/client/components/shared/page-wrapper.mjs +27 -0
  60. package/dist/client/constants.cjs +5 -0
  61. package/dist/client/constants.mjs +3 -0
  62. package/dist/client/hooks/cms-hooks.cjs +300 -0
  63. package/dist/client/hooks/cms-hooks.mjs +280 -0
  64. package/dist/client/hooks/cms-resource.cjs +13 -0
  65. package/dist/client/hooks/cms-resource.mjs +11 -0
  66. package/dist/client/hooks/index.cjs +25 -0
  67. package/dist/client/hooks/index.d.cts +693 -0
  68. package/dist/client/hooks/index.d.mts +693 -0
  69. package/dist/client/hooks/index.d.ts +693 -0
  70. package/dist/client/hooks/index.mjs +1 -0
  71. package/dist/client/index.cjs +15 -0
  72. package/dist/client/index.d.cts +654 -0
  73. package/dist/client/index.d.mts +654 -0
  74. package/dist/client/index.d.ts +654 -0
  75. package/dist/client/index.mjs +3 -0
  76. package/dist/client/overrides.cjs +26 -0
  77. package/dist/client/overrides.mjs +24 -0
  78. package/dist/client/plugin.cjs +316 -0
  79. package/dist/client/plugin.mjs +314 -0
  80. package/dist/client.css +3 -0
  81. package/dist/db.cjs +118 -0
  82. package/dist/db.mjs +116 -0
  83. package/dist/permissions.cjs +46 -0
  84. package/dist/permissions.d.cts +42 -0
  85. package/dist/permissions.d.mts +42 -0
  86. package/dist/permissions.d.ts +42 -0
  87. package/dist/permissions.mjs +44 -0
  88. package/dist/query-keys.cjs +229 -0
  89. package/dist/query-keys.d.cts +8 -0
  90. package/dist/query-keys.d.mts +8 -0
  91. package/dist/query-keys.d.ts +8 -0
  92. package/dist/query-keys.mjs +225 -0
  93. package/dist/schemas.cjs +81 -0
  94. package/dist/schemas.mjs +72 -0
  95. package/dist/shared/plugin-cms.BBshPRkb.d.cts +6 -0
  96. package/dist/shared/plugin-cms.BBshPRkb.d.mts +6 -0
  97. package/dist/shared/plugin-cms.BBshPRkb.d.ts +6 -0
  98. package/dist/shared/plugin-cms.Bptwe33B.d.cts +1749 -0
  99. package/dist/shared/plugin-cms.Csx7tNDO.d.mts +1749 -0
  100. package/dist/shared/plugin-cms.eNW9_FO5.d.ts +1749 -0
  101. package/dist/style.css +6 -0
  102. package/dist/types.cjs +2 -0
  103. package/dist/types.d.cts +406 -0
  104. package/dist/types.d.mts +406 -0
  105. package/dist/types.d.ts +406 -0
  106. package/dist/types.mjs +1 -0
  107. package/dist/ui/src/components/accordion.cjs +81 -0
  108. package/dist/ui/src/components/accordion.mjs +62 -0
  109. package/dist/ui/src/components/alert-dialog.cjs +157 -0
  110. package/dist/ui/src/components/alert-dialog.mjs +132 -0
  111. package/dist/ui/src/components/auto-form/common/label.cjs +18 -0
  112. package/dist/ui/src/components/auto-form/common/label.mjs +16 -0
  113. package/dist/ui/src/components/auto-form/common/tooltip.cjs +9 -0
  114. package/dist/ui/src/components/auto-form/common/tooltip.mjs +7 -0
  115. package/dist/ui/src/components/auto-form/config.cjs +40 -0
  116. package/dist/ui/src/components/auto-form/config.mjs +37 -0
  117. package/dist/ui/src/components/auto-form/dependencies.cjs +48 -0
  118. package/dist/ui/src/components/auto-form/dependencies.mjs +46 -0
  119. package/dist/ui/src/components/auto-form/fields/array.cjs +266 -0
  120. package/dist/ui/src/components/auto-form/fields/array.mjs +264 -0
  121. package/dist/ui/src/components/auto-form/fields/checkbox.cjs +38 -0
  122. package/dist/ui/src/components/auto-form/fields/checkbox.mjs +36 -0
  123. package/dist/ui/src/components/auto-form/fields/date.cjs +67 -0
  124. package/dist/ui/src/components/auto-form/fields/date.mjs +65 -0
  125. package/dist/ui/src/components/auto-form/fields/enum.cjs +73 -0
  126. package/dist/ui/src/components/auto-form/fields/enum.mjs +71 -0
  127. package/dist/ui/src/components/auto-form/fields/input.cjs +32 -0
  128. package/dist/ui/src/components/auto-form/fields/input.mjs +30 -0
  129. package/dist/ui/src/components/auto-form/fields/number.cjs +31 -0
  130. package/dist/ui/src/components/auto-form/fields/number.mjs +29 -0
  131. package/dist/ui/src/components/auto-form/fields/object.cjs +233 -0
  132. package/dist/ui/src/components/auto-form/fields/object.mjs +217 -0
  133. package/dist/ui/src/components/auto-form/fields/radio-group.cjs +67 -0
  134. package/dist/ui/src/components/auto-form/fields/radio-group.mjs +65 -0
  135. package/dist/ui/src/components/auto-form/fields/switch.cjs +38 -0
  136. package/dist/ui/src/components/auto-form/fields/switch.mjs +36 -0
  137. package/dist/ui/src/components/auto-form/fields/textarea.cjs +31 -0
  138. package/dist/ui/src/components/auto-form/fields/textarea.mjs +29 -0
  139. package/dist/ui/src/components/auto-form/helpers.cjs +270 -0
  140. package/dist/ui/src/components/auto-form/helpers.mjs +259 -0
  141. package/dist/ui/src/components/auto-form/index.cjs +92 -0
  142. package/dist/ui/src/components/auto-form/index.mjs +86 -0
  143. package/dist/ui/src/components/auto-form/stepped-auto-form.cjs +374 -0
  144. package/dist/ui/src/components/auto-form/stepped-auto-form.mjs +368 -0
  145. package/dist/ui/src/components/auto-form/types.cjs +11 -0
  146. package/dist/ui/src/components/auto-form/types.mjs +9 -0
  147. package/dist/ui/src/components/badge.cjs +42 -0
  148. package/dist/ui/src/components/badge.mjs +39 -0
  149. package/dist/ui/src/components/button.cjs +56 -0
  150. package/dist/ui/src/components/button.mjs +53 -0
  151. package/dist/ui/src/components/calendar.cjs +207 -0
  152. package/dist/ui/src/components/calendar.mjs +190 -0
  153. package/dist/ui/src/components/card.cjs +56 -0
  154. package/dist/ui/src/components/card.mjs +51 -0
  155. package/dist/ui/src/components/checkbox.cjs +48 -0
  156. package/dist/ui/src/components/checkbox.mjs +32 -0
  157. package/dist/ui/src/components/command.cjs +78 -0
  158. package/dist/ui/src/components/command.mjs +73 -0
  159. package/dist/ui/src/components/date-picker.cjs +41 -0
  160. package/dist/ui/src/components/date-picker.mjs +39 -0
  161. package/dist/ui/src/components/dialog.cjs +119 -0
  162. package/dist/ui/src/components/dialog.mjs +97 -0
  163. package/dist/ui/src/components/form.cjs +120 -0
  164. package/dist/ui/src/components/form.mjs +98 -0
  165. package/dist/ui/src/components/input.cjs +23 -0
  166. package/dist/ui/src/components/input.mjs +21 -0
  167. package/dist/ui/src/components/label.cjs +39 -0
  168. package/dist/ui/src/components/label.mjs +23 -0
  169. package/dist/ui/src/components/multi-select.cjs +555 -0
  170. package/dist/ui/src/components/multi-select.mjs +540 -0
  171. package/dist/ui/src/components/page-layout.cjs +25 -0
  172. package/dist/ui/src/components/page-layout.mjs +23 -0
  173. package/dist/ui/src/components/page-wrapper.cjs +20 -0
  174. package/dist/ui/src/components/page-wrapper.mjs +18 -0
  175. package/dist/ui/src/components/popover.cjs +60 -0
  176. package/dist/ui/src/components/popover.mjs +42 -0
  177. package/dist/ui/src/components/radio-group.cjs +62 -0
  178. package/dist/ui/src/components/radio-group.mjs +45 -0
  179. package/dist/ui/src/components/select.cjs +161 -0
  180. package/dist/ui/src/components/select.mjs +139 -0
  181. package/dist/ui/src/components/separator.cjs +43 -0
  182. package/dist/ui/src/components/separator.mjs +27 -0
  183. package/dist/ui/src/components/skeleton.cjs +17 -0
  184. package/dist/ui/src/components/skeleton.mjs +15 -0
  185. package/dist/ui/src/components/stack-attribution.cjs +24 -0
  186. package/dist/ui/src/components/stack-attribution.mjs +22 -0
  187. package/dist/ui/src/components/switch.cjs +48 -0
  188. package/dist/ui/src/components/switch.mjs +32 -0
  189. package/dist/ui/src/components/table.cjs +89 -0
  190. package/dist/ui/src/components/table.mjs +82 -0
  191. package/dist/ui/src/components/textarea.cjs +20 -0
  192. package/dist/ui/src/components/textarea.mjs +18 -0
  193. package/dist/ui/src/hooks/use-debounce.cjs +16 -0
  194. package/dist/ui/src/hooks/use-debounce.mjs +14 -0
  195. package/dist/ui/src/hooks/use-route-lifecycle.cjs +31 -0
  196. package/dist/ui/src/hooks/use-route-lifecycle.mjs +29 -0
  197. package/dist/ui/src/lib/schema-converter.cjs +133 -0
  198. package/dist/ui/src/lib/schema-converter.mjs +127 -0
  199. package/dist/ui/src/lib/utils.cjs +10 -0
  200. package/dist/ui/src/lib/utils.mjs +8 -0
  201. package/dist/utils.cjs +19 -0
  202. package/dist/utils.mjs +12 -0
  203. package/package.json +170 -3
  204. package/README.md +0 -3
@@ -0,0 +1,24 @@
1
+ function orderCMSContentTypes(contentTypes, providerConfig) {
2
+ const configured = providerConfig?.contentTypes;
3
+ if (!Array.isArray(configured) || configured.length === 0) {
4
+ return [...contentTypes];
5
+ }
6
+ const positions = /* @__PURE__ */ new Map();
7
+ for (const [index, value] of configured.entries()) {
8
+ if (value !== null && typeof value === "object" && "slug" in value && typeof value.slug === "string") {
9
+ positions.set(value.slug, index);
10
+ }
11
+ }
12
+ return contentTypes.map((value, index) => ({ value, index })).sort((left, right) => {
13
+ const leftPosition = positions.get(left.value.slug);
14
+ const rightPosition = positions.get(right.value.slug);
15
+ if (leftPosition === void 0 && rightPosition === void 0) {
16
+ return left.index - right.index;
17
+ }
18
+ if (leftPosition === void 0) return 1;
19
+ if (rightPosition === void 0) return -1;
20
+ return leftPosition - rightPosition;
21
+ }).map(({ value }) => value);
22
+ }
23
+
24
+ export { orderCMSContentTypes };
@@ -0,0 +1,316 @@
1
+ 'use strict';
2
+
3
+ const jsxRuntime = require('react/jsx-runtime');
4
+ const React = require('react');
5
+ const client = require('@btst/stack/plugins/client');
6
+ const yar = require('@btst/yar');
7
+ const queryKeys = require('../query-keys.cjs');
8
+ const constants = require('./constants.cjs');
9
+
10
+ const DashboardPageComponent = React.lazy(
11
+ () => import('./components/pages/dashboard-page.cjs').then((m) => ({
12
+ default: m.DashboardPageComponent
13
+ }))
14
+ );
15
+ const ContentListPageComponent = React.lazy(
16
+ () => import('./components/pages/content-list-page.cjs').then((m) => ({
17
+ default: m.ContentListPageComponent
18
+ }))
19
+ );
20
+ const ContentEditorPageComponent = React.lazy(
21
+ () => import('./components/pages/content-editor-page.cjs').then((m) => ({
22
+ default: m.ContentEditorPageComponent
23
+ }))
24
+ );
25
+ function resolveCMSClientConfig(config, runtime) {
26
+ return {
27
+ hooks: config.hooks,
28
+ pageComponents: config.pageComponents,
29
+ apiBaseURL: runtime.api.baseURL,
30
+ apiBasePath: runtime.api.basePath,
31
+ siteBaseURL: runtime.site.baseURL,
32
+ siteBasePath: runtime.site.basePath,
33
+ queryClient: runtime.queryClient,
34
+ ...runtime.api.headers ? { headers: runtime.api.headers } : {},
35
+ ...runtime.api.credentials ? { credentials: runtime.api.credentials } : {}
36
+ };
37
+ }
38
+ function createCMSApiClient(config) {
39
+ return client.createApiClient({
40
+ baseURL: config.apiBaseURL,
41
+ basePath: config.apiBasePath,
42
+ headers: config.headers,
43
+ credentials: config.credentials
44
+ });
45
+ }
46
+ function createLoadErrorReporter(hooks, context) {
47
+ let reported = false;
48
+ return async (error) => {
49
+ if (reported || !hooks?.onErrorLoad) return;
50
+ reported = true;
51
+ try {
52
+ await hooks.onErrorLoad(
53
+ error instanceof Error ? error : new Error(String(error)),
54
+ context
55
+ );
56
+ } catch {
57
+ }
58
+ };
59
+ }
60
+ function createDashboardLoader(config) {
61
+ return async () => {
62
+ if (typeof window === "undefined") {
63
+ const { queryClient, apiBasePath, apiBaseURL, headers, hooks } = config;
64
+ const context = {
65
+ path: "/cms",
66
+ isSSR: true,
67
+ apiBaseURL,
68
+ apiBasePath,
69
+ headers
70
+ };
71
+ const reportError = createLoadErrorReporter(hooks, context);
72
+ const queries = queryKeys.createCMSQueryKeys(createCMSApiClient(config));
73
+ const typesQuery = queries.cmsTypes.list();
74
+ try {
75
+ if (hooks?.beforeLoadDashboard) {
76
+ await hooks.beforeLoadDashboard(context);
77
+ }
78
+ await queryClient.prefetchQuery(typesQuery);
79
+ if (hooks?.afterLoadDashboard) {
80
+ await hooks.afterLoadDashboard(context);
81
+ }
82
+ const queryState = queryClient.getQueryState(typesQuery.queryKey);
83
+ if (queryState?.error) {
84
+ const error = queryState.error instanceof Error ? queryState.error : new Error(String(queryState.error));
85
+ await reportError(error);
86
+ }
87
+ } catch (error) {
88
+ if (client.isConnectionError(error)) {
89
+ console.warn(
90
+ "[btst/cms] route.loader() failed \u2014 no server running at build time. Use myStack.raw.cms.prefetchForRoute() for SSG data prefetching."
91
+ );
92
+ } else {
93
+ const errToStore = client.createSanitizedSSRLoaderError();
94
+ await queryClient.prefetchQuery({
95
+ queryKey: typesQuery.queryKey,
96
+ queryFn: () => {
97
+ throw errToStore;
98
+ },
99
+ retry: false
100
+ });
101
+ }
102
+ await reportError(error);
103
+ }
104
+ }
105
+ };
106
+ }
107
+ function createContentListLoader(typeSlug, config) {
108
+ return async () => {
109
+ if (typeof window === "undefined") {
110
+ const { queryClient, apiBasePath, apiBaseURL, headers, hooks } = config;
111
+ const context = {
112
+ path: `/cms/${typeSlug}`,
113
+ params: { typeSlug },
114
+ isSSR: true,
115
+ apiBaseURL,
116
+ apiBasePath,
117
+ headers
118
+ };
119
+ const reportError = createLoadErrorReporter(hooks, context);
120
+ const queries = queryKeys.createCMSQueryKeys(createCMSApiClient(config));
121
+ const limit = 20;
122
+ const typesQuery = queries.cmsTypes.list();
123
+ const listQuery = queries.cmsContent.list({ typeSlug, limit });
124
+ try {
125
+ if (hooks?.beforeLoadContentList) {
126
+ await hooks.beforeLoadContentList(typeSlug, context);
127
+ }
128
+ await queryClient.prefetchQuery(typesQuery);
129
+ await queryClient.prefetchInfiniteQuery({
130
+ ...listQuery,
131
+ initialPageParam: 0
132
+ });
133
+ if (hooks?.afterLoadContentList) {
134
+ await hooks.afterLoadContentList(typeSlug, context);
135
+ }
136
+ const typesState = queryClient.getQueryState(typesQuery.queryKey);
137
+ const listState = queryClient.getQueryState(listQuery.queryKey);
138
+ const queryError = typesState?.error || listState?.error;
139
+ if (queryError) {
140
+ const error = queryError instanceof Error ? queryError : new Error(String(queryError));
141
+ await reportError(error);
142
+ }
143
+ } catch (error) {
144
+ if (client.isConnectionError(error)) {
145
+ console.warn(
146
+ "[btst/cms] route.loader() failed \u2014 no server running at build time. Use myStack.raw.cms.prefetchForRoute() for SSG data prefetching."
147
+ );
148
+ } else {
149
+ const errToStore = client.createSanitizedSSRLoaderError();
150
+ await queryClient.prefetchInfiniteQuery({
151
+ queryKey: listQuery.queryKey,
152
+ queryFn: () => {
153
+ throw errToStore;
154
+ },
155
+ initialPageParam: 0,
156
+ retry: false
157
+ });
158
+ }
159
+ await reportError(error);
160
+ }
161
+ }
162
+ };
163
+ }
164
+ function createContentEditorLoader(typeSlug, id, config) {
165
+ return async () => {
166
+ if (typeof window === "undefined") {
167
+ const { queryClient, apiBasePath, apiBaseURL, headers, hooks } = config;
168
+ const context = {
169
+ path: id ? `/cms/${typeSlug}/${id}` : `/cms/${typeSlug}/new`,
170
+ params: id ? { typeSlug, id } : { typeSlug },
171
+ isSSR: true,
172
+ apiBaseURL,
173
+ apiBasePath,
174
+ headers
175
+ };
176
+ const reportError = createLoadErrorReporter(hooks, context);
177
+ const queries = queryKeys.createCMSQueryKeys(createCMSApiClient(config));
178
+ const typesQuery = queries.cmsTypes.list();
179
+ const detailQuery = id ? queries.cmsContent.detail(typeSlug, id) : void 0;
180
+ try {
181
+ if (hooks?.beforeLoadContentEditor) {
182
+ await hooks.beforeLoadContentEditor(typeSlug, id, context);
183
+ }
184
+ const promises = [queryClient.prefetchQuery(typesQuery)];
185
+ if (id) {
186
+ promises.push(queryClient.prefetchQuery(detailQuery));
187
+ }
188
+ await Promise.all(promises);
189
+ if (hooks?.afterLoadContentEditor) {
190
+ await hooks.afterLoadContentEditor(typeSlug, id, context);
191
+ }
192
+ const typesState = queryClient.getQueryState(typesQuery.queryKey);
193
+ const itemState = id ? queryClient.getQueryState(detailQuery.queryKey) : null;
194
+ const queryError = typesState?.error || itemState?.error;
195
+ if (queryError) {
196
+ const error = queryError instanceof Error ? queryError : new Error(String(queryError));
197
+ await reportError(error);
198
+ }
199
+ } catch (error) {
200
+ if (client.isConnectionError(error)) {
201
+ console.warn(
202
+ "[btst/cms] route.loader() failed \u2014 no server running at build time. Use myStack.raw.cms.prefetchForRoute() for SSG data prefetching."
203
+ );
204
+ } else {
205
+ const errToStore = client.createSanitizedSSRLoaderError();
206
+ await queryClient.prefetchQuery({
207
+ queryKey: typesQuery.queryKey,
208
+ queryFn: () => {
209
+ throw errToStore;
210
+ },
211
+ retry: false
212
+ });
213
+ if (detailQuery) {
214
+ await queryClient.prefetchQuery({
215
+ queryKey: detailQuery.queryKey,
216
+ queryFn: () => {
217
+ throw errToStore;
218
+ },
219
+ retry: false
220
+ });
221
+ }
222
+ }
223
+ await reportError(error);
224
+ }
225
+ }
226
+ };
227
+ }
228
+ function createDashboardMeta() {
229
+ return () => {
230
+ const title = "CMS Dashboard";
231
+ return [
232
+ { title },
233
+ { name: "title", content: title },
234
+ { name: "robots", content: "noindex" }
235
+ ];
236
+ };
237
+ }
238
+ function createContentListMeta(typeSlug, config) {
239
+ return () => {
240
+ const { queryClient } = config;
241
+ const queries = queryKeys.createCMSQueryKeys(createCMSApiClient(config));
242
+ const contentTypes = queryClient.getQueryData(
243
+ queries.cmsTypes.list().queryKey
244
+ );
245
+ const contentType = contentTypes?.find((ct) => ct.slug === typeSlug);
246
+ const title = contentType?.name ? `${contentType.name} | CMS` : "Content | CMS";
247
+ return [
248
+ { title },
249
+ { name: "title", content: title },
250
+ { name: "robots", content: "noindex" }
251
+ ];
252
+ };
253
+ }
254
+ function createContentEditorMeta(typeSlug, id, config) {
255
+ return () => {
256
+ const { queryClient } = config;
257
+ const queries = queryKeys.createCMSQueryKeys(createCMSApiClient(config));
258
+ const contentTypes = queryClient.getQueryData(
259
+ queries.cmsTypes.list().queryKey
260
+ );
261
+ const contentType = contentTypes?.find((ct) => ct.slug === typeSlug);
262
+ const title = id ? `Edit ${contentType?.name || "Content"} | CMS` : `New ${contentType?.name || "Content"} | CMS`;
263
+ return [
264
+ { title },
265
+ { name: "title", content: title },
266
+ { name: "robots", content: "noindex" }
267
+ ];
268
+ };
269
+ }
270
+ function createResolvedCMSPlugin(config) {
271
+ return {
272
+ routes: () => yar.defineRoutes(
273
+ {
274
+ dashboard: yar.defineRoute("/cms", {
275
+ page: DashboardPageComponent,
276
+ loader: createDashboardLoader(config),
277
+ meta: createDashboardMeta()
278
+ }),
279
+ contentList: yar.defineRoute("/cms/:typeSlug", {
280
+ page: ({ params }) => /* @__PURE__ */ jsxRuntime.jsx(ContentListPageComponent, { typeSlug: params.typeSlug }),
281
+ loader: ({ params }) => createContentListLoader(params.typeSlug, config)(),
282
+ meta: ({ params }) => createContentListMeta(params.typeSlug, config)()
283
+ }),
284
+ newContent: yar.defineRoute("/cms/:typeSlug/new", {
285
+ page: ({ params }) => /* @__PURE__ */ jsxRuntime.jsx(ContentEditorPageComponent, { typeSlug: params.typeSlug }),
286
+ loader: ({ params }) => createContentEditorLoader(params.typeSlug, void 0, config)(),
287
+ meta: ({ params }) => createContentEditorMeta(params.typeSlug, void 0, config)()
288
+ }),
289
+ editContent: yar.defineRoute("/cms/:typeSlug/:id", {
290
+ page: ({ params }) => /* @__PURE__ */ jsxRuntime.jsx(
291
+ ContentEditorPageComponent,
292
+ {
293
+ typeSlug: params.typeSlug,
294
+ id: params.id
295
+ }
296
+ ),
297
+ loader: ({ params }) => createContentEditorLoader(params.typeSlug, params.id, config)(),
298
+ meta: ({ params }) => createContentEditorMeta(params.typeSlug, params.id, config)()
299
+ })
300
+ },
301
+ { pages: config.pageComponents }
302
+ ),
303
+ sitemap: async () => {
304
+ return [];
305
+ }
306
+ };
307
+ }
308
+ const cmsClientPlugin = (config = {}) => client.defineClientPlugin()({
309
+ id: constants.CMS_PLUGIN_ID,
310
+ providerConfig: {
311
+ ...config.contentTypes ? { contentTypes: config.contentTypes } : {}
312
+ },
313
+ resolve: (runtime) => createResolvedCMSPlugin(resolveCMSClientConfig(config, runtime))
314
+ });
315
+
316
+ exports.cmsClientPlugin = cmsClientPlugin;
@@ -0,0 +1,314 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { lazy } from 'react';
3
+ import { defineClientPlugin, isConnectionError, createSanitizedSSRLoaderError, createApiClient } from '@btst/stack/plugins/client';
4
+ import { defineRoutes, defineRoute } from '@btst/yar';
5
+ import { createCMSQueryKeys } from '../query-keys.mjs';
6
+ import { CMS_PLUGIN_ID } from './constants.mjs';
7
+
8
+ const DashboardPageComponent = lazy(
9
+ () => import('./components/pages/dashboard-page.mjs').then((m) => ({
10
+ default: m.DashboardPageComponent
11
+ }))
12
+ );
13
+ const ContentListPageComponent = lazy(
14
+ () => import('./components/pages/content-list-page.mjs').then((m) => ({
15
+ default: m.ContentListPageComponent
16
+ }))
17
+ );
18
+ const ContentEditorPageComponent = lazy(
19
+ () => import('./components/pages/content-editor-page.mjs').then((m) => ({
20
+ default: m.ContentEditorPageComponent
21
+ }))
22
+ );
23
+ function resolveCMSClientConfig(config, runtime) {
24
+ return {
25
+ hooks: config.hooks,
26
+ pageComponents: config.pageComponents,
27
+ apiBaseURL: runtime.api.baseURL,
28
+ apiBasePath: runtime.api.basePath,
29
+ siteBaseURL: runtime.site.baseURL,
30
+ siteBasePath: runtime.site.basePath,
31
+ queryClient: runtime.queryClient,
32
+ ...runtime.api.headers ? { headers: runtime.api.headers } : {},
33
+ ...runtime.api.credentials ? { credentials: runtime.api.credentials } : {}
34
+ };
35
+ }
36
+ function createCMSApiClient(config) {
37
+ return createApiClient({
38
+ baseURL: config.apiBaseURL,
39
+ basePath: config.apiBasePath,
40
+ headers: config.headers,
41
+ credentials: config.credentials
42
+ });
43
+ }
44
+ function createLoadErrorReporter(hooks, context) {
45
+ let reported = false;
46
+ return async (error) => {
47
+ if (reported || !hooks?.onErrorLoad) return;
48
+ reported = true;
49
+ try {
50
+ await hooks.onErrorLoad(
51
+ error instanceof Error ? error : new Error(String(error)),
52
+ context
53
+ );
54
+ } catch {
55
+ }
56
+ };
57
+ }
58
+ function createDashboardLoader(config) {
59
+ return async () => {
60
+ if (typeof window === "undefined") {
61
+ const { queryClient, apiBasePath, apiBaseURL, headers, hooks } = config;
62
+ const context = {
63
+ path: "/cms",
64
+ isSSR: true,
65
+ apiBaseURL,
66
+ apiBasePath,
67
+ headers
68
+ };
69
+ const reportError = createLoadErrorReporter(hooks, context);
70
+ const queries = createCMSQueryKeys(createCMSApiClient(config));
71
+ const typesQuery = queries.cmsTypes.list();
72
+ try {
73
+ if (hooks?.beforeLoadDashboard) {
74
+ await hooks.beforeLoadDashboard(context);
75
+ }
76
+ await queryClient.prefetchQuery(typesQuery);
77
+ if (hooks?.afterLoadDashboard) {
78
+ await hooks.afterLoadDashboard(context);
79
+ }
80
+ const queryState = queryClient.getQueryState(typesQuery.queryKey);
81
+ if (queryState?.error) {
82
+ const error = queryState.error instanceof Error ? queryState.error : new Error(String(queryState.error));
83
+ await reportError(error);
84
+ }
85
+ } catch (error) {
86
+ if (isConnectionError(error)) {
87
+ console.warn(
88
+ "[btst/cms] route.loader() failed \u2014 no server running at build time. Use myStack.raw.cms.prefetchForRoute() for SSG data prefetching."
89
+ );
90
+ } else {
91
+ const errToStore = createSanitizedSSRLoaderError();
92
+ await queryClient.prefetchQuery({
93
+ queryKey: typesQuery.queryKey,
94
+ queryFn: () => {
95
+ throw errToStore;
96
+ },
97
+ retry: false
98
+ });
99
+ }
100
+ await reportError(error);
101
+ }
102
+ }
103
+ };
104
+ }
105
+ function createContentListLoader(typeSlug, config) {
106
+ return async () => {
107
+ if (typeof window === "undefined") {
108
+ const { queryClient, apiBasePath, apiBaseURL, headers, hooks } = config;
109
+ const context = {
110
+ path: `/cms/${typeSlug}`,
111
+ params: { typeSlug },
112
+ isSSR: true,
113
+ apiBaseURL,
114
+ apiBasePath,
115
+ headers
116
+ };
117
+ const reportError = createLoadErrorReporter(hooks, context);
118
+ const queries = createCMSQueryKeys(createCMSApiClient(config));
119
+ const limit = 20;
120
+ const typesQuery = queries.cmsTypes.list();
121
+ const listQuery = queries.cmsContent.list({ typeSlug, limit });
122
+ try {
123
+ if (hooks?.beforeLoadContentList) {
124
+ await hooks.beforeLoadContentList(typeSlug, context);
125
+ }
126
+ await queryClient.prefetchQuery(typesQuery);
127
+ await queryClient.prefetchInfiniteQuery({
128
+ ...listQuery,
129
+ initialPageParam: 0
130
+ });
131
+ if (hooks?.afterLoadContentList) {
132
+ await hooks.afterLoadContentList(typeSlug, context);
133
+ }
134
+ const typesState = queryClient.getQueryState(typesQuery.queryKey);
135
+ const listState = queryClient.getQueryState(listQuery.queryKey);
136
+ const queryError = typesState?.error || listState?.error;
137
+ if (queryError) {
138
+ const error = queryError instanceof Error ? queryError : new Error(String(queryError));
139
+ await reportError(error);
140
+ }
141
+ } catch (error) {
142
+ if (isConnectionError(error)) {
143
+ console.warn(
144
+ "[btst/cms] route.loader() failed \u2014 no server running at build time. Use myStack.raw.cms.prefetchForRoute() for SSG data prefetching."
145
+ );
146
+ } else {
147
+ const errToStore = createSanitizedSSRLoaderError();
148
+ await queryClient.prefetchInfiniteQuery({
149
+ queryKey: listQuery.queryKey,
150
+ queryFn: () => {
151
+ throw errToStore;
152
+ },
153
+ initialPageParam: 0,
154
+ retry: false
155
+ });
156
+ }
157
+ await reportError(error);
158
+ }
159
+ }
160
+ };
161
+ }
162
+ function createContentEditorLoader(typeSlug, id, config) {
163
+ return async () => {
164
+ if (typeof window === "undefined") {
165
+ const { queryClient, apiBasePath, apiBaseURL, headers, hooks } = config;
166
+ const context = {
167
+ path: id ? `/cms/${typeSlug}/${id}` : `/cms/${typeSlug}/new`,
168
+ params: id ? { typeSlug, id } : { typeSlug },
169
+ isSSR: true,
170
+ apiBaseURL,
171
+ apiBasePath,
172
+ headers
173
+ };
174
+ const reportError = createLoadErrorReporter(hooks, context);
175
+ const queries = createCMSQueryKeys(createCMSApiClient(config));
176
+ const typesQuery = queries.cmsTypes.list();
177
+ const detailQuery = id ? queries.cmsContent.detail(typeSlug, id) : void 0;
178
+ try {
179
+ if (hooks?.beforeLoadContentEditor) {
180
+ await hooks.beforeLoadContentEditor(typeSlug, id, context);
181
+ }
182
+ const promises = [queryClient.prefetchQuery(typesQuery)];
183
+ if (id) {
184
+ promises.push(queryClient.prefetchQuery(detailQuery));
185
+ }
186
+ await Promise.all(promises);
187
+ if (hooks?.afterLoadContentEditor) {
188
+ await hooks.afterLoadContentEditor(typeSlug, id, context);
189
+ }
190
+ const typesState = queryClient.getQueryState(typesQuery.queryKey);
191
+ const itemState = id ? queryClient.getQueryState(detailQuery.queryKey) : null;
192
+ const queryError = typesState?.error || itemState?.error;
193
+ if (queryError) {
194
+ const error = queryError instanceof Error ? queryError : new Error(String(queryError));
195
+ await reportError(error);
196
+ }
197
+ } catch (error) {
198
+ if (isConnectionError(error)) {
199
+ console.warn(
200
+ "[btst/cms] route.loader() failed \u2014 no server running at build time. Use myStack.raw.cms.prefetchForRoute() for SSG data prefetching."
201
+ );
202
+ } else {
203
+ const errToStore = createSanitizedSSRLoaderError();
204
+ await queryClient.prefetchQuery({
205
+ queryKey: typesQuery.queryKey,
206
+ queryFn: () => {
207
+ throw errToStore;
208
+ },
209
+ retry: false
210
+ });
211
+ if (detailQuery) {
212
+ await queryClient.prefetchQuery({
213
+ queryKey: detailQuery.queryKey,
214
+ queryFn: () => {
215
+ throw errToStore;
216
+ },
217
+ retry: false
218
+ });
219
+ }
220
+ }
221
+ await reportError(error);
222
+ }
223
+ }
224
+ };
225
+ }
226
+ function createDashboardMeta() {
227
+ return () => {
228
+ const title = "CMS Dashboard";
229
+ return [
230
+ { title },
231
+ { name: "title", content: title },
232
+ { name: "robots", content: "noindex" }
233
+ ];
234
+ };
235
+ }
236
+ function createContentListMeta(typeSlug, config) {
237
+ return () => {
238
+ const { queryClient } = config;
239
+ const queries = createCMSQueryKeys(createCMSApiClient(config));
240
+ const contentTypes = queryClient.getQueryData(
241
+ queries.cmsTypes.list().queryKey
242
+ );
243
+ const contentType = contentTypes?.find((ct) => ct.slug === typeSlug);
244
+ const title = contentType?.name ? `${contentType.name} | CMS` : "Content | CMS";
245
+ return [
246
+ { title },
247
+ { name: "title", content: title },
248
+ { name: "robots", content: "noindex" }
249
+ ];
250
+ };
251
+ }
252
+ function createContentEditorMeta(typeSlug, id, config) {
253
+ return () => {
254
+ const { queryClient } = config;
255
+ const queries = createCMSQueryKeys(createCMSApiClient(config));
256
+ const contentTypes = queryClient.getQueryData(
257
+ queries.cmsTypes.list().queryKey
258
+ );
259
+ const contentType = contentTypes?.find((ct) => ct.slug === typeSlug);
260
+ const title = id ? `Edit ${contentType?.name || "Content"} | CMS` : `New ${contentType?.name || "Content"} | CMS`;
261
+ return [
262
+ { title },
263
+ { name: "title", content: title },
264
+ { name: "robots", content: "noindex" }
265
+ ];
266
+ };
267
+ }
268
+ function createResolvedCMSPlugin(config) {
269
+ return {
270
+ routes: () => defineRoutes(
271
+ {
272
+ dashboard: defineRoute("/cms", {
273
+ page: DashboardPageComponent,
274
+ loader: createDashboardLoader(config),
275
+ meta: createDashboardMeta()
276
+ }),
277
+ contentList: defineRoute("/cms/:typeSlug", {
278
+ page: ({ params }) => /* @__PURE__ */ jsx(ContentListPageComponent, { typeSlug: params.typeSlug }),
279
+ loader: ({ params }) => createContentListLoader(params.typeSlug, config)(),
280
+ meta: ({ params }) => createContentListMeta(params.typeSlug, config)()
281
+ }),
282
+ newContent: defineRoute("/cms/:typeSlug/new", {
283
+ page: ({ params }) => /* @__PURE__ */ jsx(ContentEditorPageComponent, { typeSlug: params.typeSlug }),
284
+ loader: ({ params }) => createContentEditorLoader(params.typeSlug, void 0, config)(),
285
+ meta: ({ params }) => createContentEditorMeta(params.typeSlug, void 0, config)()
286
+ }),
287
+ editContent: defineRoute("/cms/:typeSlug/:id", {
288
+ page: ({ params }) => /* @__PURE__ */ jsx(
289
+ ContentEditorPageComponent,
290
+ {
291
+ typeSlug: params.typeSlug,
292
+ id: params.id
293
+ }
294
+ ),
295
+ loader: ({ params }) => createContentEditorLoader(params.typeSlug, params.id, config)(),
296
+ meta: ({ params }) => createContentEditorMeta(params.typeSlug, params.id, config)()
297
+ })
298
+ },
299
+ { pages: config.pageComponents }
300
+ ),
301
+ sitemap: async () => {
302
+ return [];
303
+ }
304
+ };
305
+ }
306
+ const cmsClientPlugin = (config = {}) => defineClientPlugin()({
307
+ id: CMS_PLUGIN_ID,
308
+ providerConfig: {
309
+ ...config.contentTypes ? { contentTypes: config.contentTypes } : {}
310
+ },
311
+ resolve: (runtime) => createResolvedCMSPlugin(resolveCMSClientConfig(config, runtime))
312
+ });
313
+
314
+ export { cmsClientPlugin };
@@ -0,0 +1,3 @@
1
+
2
+ /* CMS Plugin Client CSS */
3
+ /* No custom styles needed - uses shadcn/ui components */