@btst/stack 1.8.0 → 1.9.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 (44) hide show
  1. package/dist/packages/better-stack/src/plugins/cms/api/plugin.cjs +445 -16
  2. package/dist/packages/better-stack/src/plugins/cms/api/plugin.mjs +445 -16
  3. package/dist/packages/better-stack/src/plugins/cms/client/components/forms/content-form.cjs +24 -7
  4. package/dist/packages/better-stack/src/plugins/cms/client/components/forms/content-form.mjs +25 -8
  5. package/dist/packages/better-stack/src/plugins/cms/client/components/forms/relation-field.cjs +224 -0
  6. package/dist/packages/better-stack/src/plugins/cms/client/components/forms/relation-field.mjs +222 -0
  7. package/dist/packages/better-stack/src/plugins/cms/client/components/inverse-relations-panel.cjs +243 -0
  8. package/dist/packages/better-stack/src/plugins/cms/client/components/inverse-relations-panel.mjs +241 -0
  9. package/dist/packages/better-stack/src/plugins/cms/client/components/pages/content-editor-page.internal.cjs +56 -2
  10. package/dist/packages/better-stack/src/plugins/cms/client/components/pages/content-editor-page.internal.mjs +56 -2
  11. package/dist/packages/better-stack/src/plugins/cms/client/hooks/cms-hooks.cjs +190 -0
  12. package/dist/packages/better-stack/src/plugins/cms/client/hooks/cms-hooks.mjs +187 -1
  13. package/dist/packages/better-stack/src/plugins/cms/db.cjs +38 -0
  14. package/dist/packages/better-stack/src/plugins/cms/db.mjs +38 -0
  15. package/dist/packages/ui/src/components/auto-form/fields/object.cjs +81 -1
  16. package/dist/packages/ui/src/components/auto-form/fields/object.mjs +81 -1
  17. package/dist/packages/ui/src/components/dialog.cjs +6 -0
  18. package/dist/packages/ui/src/components/dialog.mjs +6 -1
  19. package/dist/plugins/cms/api/index.d.cts +67 -3
  20. package/dist/plugins/cms/api/index.d.mts +67 -3
  21. package/dist/plugins/cms/api/index.d.ts +67 -3
  22. package/dist/plugins/cms/client/hooks/index.cjs +4 -0
  23. package/dist/plugins/cms/client/hooks/index.d.cts +82 -3
  24. package/dist/plugins/cms/client/hooks/index.d.mts +82 -3
  25. package/dist/plugins/cms/client/hooks/index.d.ts +82 -3
  26. package/dist/plugins/cms/client/hooks/index.mjs +1 -1
  27. package/dist/plugins/cms/query-keys.d.cts +1 -1
  28. package/dist/plugins/cms/query-keys.d.mts +1 -1
  29. package/dist/plugins/cms/query-keys.d.ts +1 -1
  30. package/dist/plugins/form-builder/api/index.d.cts +1 -1
  31. package/dist/plugins/form-builder/api/index.d.mts +1 -1
  32. package/dist/plugins/form-builder/api/index.d.ts +1 -1
  33. package/dist/shared/{stack.L-UFwz2G.d.cts → stack.oGOteE6g.d.cts} +27 -5
  34. package/dist/shared/{stack.L-UFwz2G.d.mts → stack.oGOteE6g.d.mts} +27 -5
  35. package/dist/shared/{stack.L-UFwz2G.d.ts → stack.oGOteE6g.d.ts} +27 -5
  36. package/package.json +1 -1
  37. package/src/plugins/cms/api/plugin.ts +667 -21
  38. package/src/plugins/cms/client/components/forms/content-form.tsx +60 -18
  39. package/src/plugins/cms/client/components/forms/relation-field.tsx +299 -0
  40. package/src/plugins/cms/client/components/inverse-relations-panel.tsx +329 -0
  41. package/src/plugins/cms/client/components/pages/content-editor-page.internal.tsx +127 -1
  42. package/src/plugins/cms/client/hooks/cms-hooks.tsx +344 -0
  43. package/src/plugins/cms/db.ts +38 -0
  44. package/src/plugins/cms/types.ts +99 -10
@@ -25,6 +25,11 @@ function Dialog({
25
25
  }) {
26
26
  return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Root, { "data-slot": "dialog", ...props });
27
27
  }
28
+ function DialogTrigger({
29
+ ...props
30
+ }) {
31
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Trigger, { "data-slot": "dialog-trigger", ...props });
32
+ }
28
33
  function DialogPortal({
29
34
  ...props
30
35
  }) {
@@ -139,3 +144,4 @@ exports.DialogHeader = DialogHeader;
139
144
  exports.DialogOverlay = DialogOverlay;
140
145
  exports.DialogPortal = DialogPortal;
141
146
  exports.DialogTitle = DialogTitle;
147
+ exports.DialogTrigger = DialogTrigger;
@@ -9,6 +9,11 @@ function Dialog({
9
9
  }) {
10
10
  return /* @__PURE__ */ jsx(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
11
11
  }
12
+ function DialogTrigger({
13
+ ...props
14
+ }) {
15
+ return /* @__PURE__ */ jsx(DialogPrimitive.Trigger, { "data-slot": "dialog-trigger", ...props });
16
+ }
12
17
  function DialogPortal({
13
18
  ...props
14
19
  }) {
@@ -115,4 +120,4 @@ function DialogDescription({
115
120
  );
116
121
  }
117
122
 
118
- export { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle };
123
+ export { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger };
@@ -1,7 +1,7 @@
1
1
  import * as _btst_stack_plugins_api from '@btst/stack/plugins/api';
2
2
  import * as better_call from 'better-call';
3
3
  import { z } from 'zod';
4
- import { C as CMSBackendConfig, S as SerializedContentType, a as SerializedContentItemWithType } from '../../../shared/stack.L-UFwz2G.cjs';
4
+ import { C as CMSBackendConfig, S as SerializedContentType, a as SerializedContentItemWithType, I as InverseRelation } from '../../../shared/stack.oGOteE6g.cjs';
5
5
 
6
6
  /**
7
7
  * CMS backend plugin
@@ -16,8 +16,8 @@ declare const cmsBackendPlugin: (config: CMSBackendConfig) => _btst_stack_plugin
16
16
  itemCount: number;
17
17
  createdAt: string;
18
18
  updatedAt: string;
19
- name: string;
20
19
  id: string;
20
+ name: string;
21
21
  slug: string;
22
22
  description?: string | undefined;
23
23
  jsonSchema: string;
@@ -63,7 +63,7 @@ declare const cmsBackendPlugin: (config: CMSBackendConfig) => _btst_stack_plugin
63
63
  data: z.ZodObject<{}, z.core.$loose>;
64
64
  }, z.core.$strip>;
65
65
  }, {
66
- parsedData: unknown;
66
+ parsedData: Record<string, unknown>;
67
67
  createdAt: string;
68
68
  updatedAt: string;
69
69
  id: string;
@@ -92,6 +92,70 @@ declare const cmsBackendPlugin: (config: CMSBackendConfig) => _btst_stack_plugin
92
92
  }, {
93
93
  success: boolean;
94
94
  }>;
95
+ getContentItemPopulated: better_call.StrictEndpoint<"/content/:typeSlug/:id/populated", {
96
+ method: "GET";
97
+ params: z.ZodObject<{
98
+ typeSlug: z.ZodString;
99
+ id: z.ZodString;
100
+ }, z.core.$strip>;
101
+ }, {
102
+ _relations: Record<string, SerializedContentItemWithType<Record<string, unknown>>[]>;
103
+ parsedData: Record<string, unknown>;
104
+ contentType?: SerializedContentType;
105
+ createdAt: string;
106
+ updatedAt: string;
107
+ id: string;
108
+ slug: string;
109
+ contentTypeId: string;
110
+ data: string;
111
+ authorId?: string | undefined;
112
+ }>;
113
+ listContentByRelation: better_call.StrictEndpoint<"/content/:typeSlug/by-relation", {
114
+ method: "GET";
115
+ params: z.ZodObject<{
116
+ typeSlug: z.ZodString;
117
+ }, z.core.$strip>;
118
+ query: z.ZodObject<{
119
+ field: z.ZodString;
120
+ targetId: z.ZodString;
121
+ limit: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
122
+ offset: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
123
+ }, z.core.$strip>;
124
+ }, {
125
+ items: SerializedContentItemWithType<Record<string, unknown>>[];
126
+ total: number;
127
+ limit: number;
128
+ offset: number;
129
+ }>;
130
+ getInverseRelations: better_call.StrictEndpoint<"/content-types/:slug/inverse-relations", {
131
+ method: "GET";
132
+ params: z.ZodObject<{
133
+ slug: z.ZodString;
134
+ }, z.core.$strip>;
135
+ query: z.ZodObject<{
136
+ itemId: z.ZodOptional<z.ZodString>;
137
+ }, z.core.$strip>;
138
+ }, {
139
+ inverseRelations: InverseRelation[];
140
+ }>;
141
+ listInverseRelationItems: better_call.StrictEndpoint<"/content-types/:slug/inverse-relations/:sourceType", {
142
+ method: "GET";
143
+ params: z.ZodObject<{
144
+ slug: z.ZodString;
145
+ sourceType: z.ZodString;
146
+ }, z.core.$strip>;
147
+ query: z.ZodObject<{
148
+ itemId: z.ZodString;
149
+ fieldName: z.ZodString;
150
+ limit: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
151
+ offset: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
152
+ }, z.core.$strip>;
153
+ }, {
154
+ items: SerializedContentItemWithType<Record<string, unknown>>[];
155
+ total: number;
156
+ limit: number;
157
+ offset: number;
158
+ }>;
95
159
  }>;
96
160
  type CMSApiRouter = ReturnType<ReturnType<typeof cmsBackendPlugin>["routes"]>;
97
161
 
@@ -1,7 +1,7 @@
1
1
  import * as _btst_stack_plugins_api from '@btst/stack/plugins/api';
2
2
  import * as better_call from 'better-call';
3
3
  import { z } from 'zod';
4
- import { C as CMSBackendConfig, S as SerializedContentType, a as SerializedContentItemWithType } from '../../../shared/stack.L-UFwz2G.mjs';
4
+ import { C as CMSBackendConfig, S as SerializedContentType, a as SerializedContentItemWithType, I as InverseRelation } from '../../../shared/stack.oGOteE6g.mjs';
5
5
 
6
6
  /**
7
7
  * CMS backend plugin
@@ -16,8 +16,8 @@ declare const cmsBackendPlugin: (config: CMSBackendConfig) => _btst_stack_plugin
16
16
  itemCount: number;
17
17
  createdAt: string;
18
18
  updatedAt: string;
19
- name: string;
20
19
  id: string;
20
+ name: string;
21
21
  slug: string;
22
22
  description?: string | undefined;
23
23
  jsonSchema: string;
@@ -63,7 +63,7 @@ declare const cmsBackendPlugin: (config: CMSBackendConfig) => _btst_stack_plugin
63
63
  data: z.ZodObject<{}, z.core.$loose>;
64
64
  }, z.core.$strip>;
65
65
  }, {
66
- parsedData: unknown;
66
+ parsedData: Record<string, unknown>;
67
67
  createdAt: string;
68
68
  updatedAt: string;
69
69
  id: string;
@@ -92,6 +92,70 @@ declare const cmsBackendPlugin: (config: CMSBackendConfig) => _btst_stack_plugin
92
92
  }, {
93
93
  success: boolean;
94
94
  }>;
95
+ getContentItemPopulated: better_call.StrictEndpoint<"/content/:typeSlug/:id/populated", {
96
+ method: "GET";
97
+ params: z.ZodObject<{
98
+ typeSlug: z.ZodString;
99
+ id: z.ZodString;
100
+ }, z.core.$strip>;
101
+ }, {
102
+ _relations: Record<string, SerializedContentItemWithType<Record<string, unknown>>[]>;
103
+ parsedData: Record<string, unknown>;
104
+ contentType?: SerializedContentType;
105
+ createdAt: string;
106
+ updatedAt: string;
107
+ id: string;
108
+ slug: string;
109
+ contentTypeId: string;
110
+ data: string;
111
+ authorId?: string | undefined;
112
+ }>;
113
+ listContentByRelation: better_call.StrictEndpoint<"/content/:typeSlug/by-relation", {
114
+ method: "GET";
115
+ params: z.ZodObject<{
116
+ typeSlug: z.ZodString;
117
+ }, z.core.$strip>;
118
+ query: z.ZodObject<{
119
+ field: z.ZodString;
120
+ targetId: z.ZodString;
121
+ limit: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
122
+ offset: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
123
+ }, z.core.$strip>;
124
+ }, {
125
+ items: SerializedContentItemWithType<Record<string, unknown>>[];
126
+ total: number;
127
+ limit: number;
128
+ offset: number;
129
+ }>;
130
+ getInverseRelations: better_call.StrictEndpoint<"/content-types/:slug/inverse-relations", {
131
+ method: "GET";
132
+ params: z.ZodObject<{
133
+ slug: z.ZodString;
134
+ }, z.core.$strip>;
135
+ query: z.ZodObject<{
136
+ itemId: z.ZodOptional<z.ZodString>;
137
+ }, z.core.$strip>;
138
+ }, {
139
+ inverseRelations: InverseRelation[];
140
+ }>;
141
+ listInverseRelationItems: better_call.StrictEndpoint<"/content-types/:slug/inverse-relations/:sourceType", {
142
+ method: "GET";
143
+ params: z.ZodObject<{
144
+ slug: z.ZodString;
145
+ sourceType: z.ZodString;
146
+ }, z.core.$strip>;
147
+ query: z.ZodObject<{
148
+ itemId: z.ZodString;
149
+ fieldName: z.ZodString;
150
+ limit: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
151
+ offset: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
152
+ }, z.core.$strip>;
153
+ }, {
154
+ items: SerializedContentItemWithType<Record<string, unknown>>[];
155
+ total: number;
156
+ limit: number;
157
+ offset: number;
158
+ }>;
95
159
  }>;
96
160
  type CMSApiRouter = ReturnType<ReturnType<typeof cmsBackendPlugin>["routes"]>;
97
161
 
@@ -1,7 +1,7 @@
1
1
  import * as _btst_stack_plugins_api from '@btst/stack/plugins/api';
2
2
  import * as better_call from 'better-call';
3
3
  import { z } from 'zod';
4
- import { C as CMSBackendConfig, S as SerializedContentType, a as SerializedContentItemWithType } from '../../../shared/stack.L-UFwz2G.js';
4
+ import { C as CMSBackendConfig, S as SerializedContentType, a as SerializedContentItemWithType, I as InverseRelation } from '../../../shared/stack.oGOteE6g.js';
5
5
 
6
6
  /**
7
7
  * CMS backend plugin
@@ -16,8 +16,8 @@ declare const cmsBackendPlugin: (config: CMSBackendConfig) => _btst_stack_plugin
16
16
  itemCount: number;
17
17
  createdAt: string;
18
18
  updatedAt: string;
19
- name: string;
20
19
  id: string;
20
+ name: string;
21
21
  slug: string;
22
22
  description?: string | undefined;
23
23
  jsonSchema: string;
@@ -63,7 +63,7 @@ declare const cmsBackendPlugin: (config: CMSBackendConfig) => _btst_stack_plugin
63
63
  data: z.ZodObject<{}, z.core.$loose>;
64
64
  }, z.core.$strip>;
65
65
  }, {
66
- parsedData: unknown;
66
+ parsedData: Record<string, unknown>;
67
67
  createdAt: string;
68
68
  updatedAt: string;
69
69
  id: string;
@@ -92,6 +92,70 @@ declare const cmsBackendPlugin: (config: CMSBackendConfig) => _btst_stack_plugin
92
92
  }, {
93
93
  success: boolean;
94
94
  }>;
95
+ getContentItemPopulated: better_call.StrictEndpoint<"/content/:typeSlug/:id/populated", {
96
+ method: "GET";
97
+ params: z.ZodObject<{
98
+ typeSlug: z.ZodString;
99
+ id: z.ZodString;
100
+ }, z.core.$strip>;
101
+ }, {
102
+ _relations: Record<string, SerializedContentItemWithType<Record<string, unknown>>[]>;
103
+ parsedData: Record<string, unknown>;
104
+ contentType?: SerializedContentType;
105
+ createdAt: string;
106
+ updatedAt: string;
107
+ id: string;
108
+ slug: string;
109
+ contentTypeId: string;
110
+ data: string;
111
+ authorId?: string | undefined;
112
+ }>;
113
+ listContentByRelation: better_call.StrictEndpoint<"/content/:typeSlug/by-relation", {
114
+ method: "GET";
115
+ params: z.ZodObject<{
116
+ typeSlug: z.ZodString;
117
+ }, z.core.$strip>;
118
+ query: z.ZodObject<{
119
+ field: z.ZodString;
120
+ targetId: z.ZodString;
121
+ limit: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
122
+ offset: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
123
+ }, z.core.$strip>;
124
+ }, {
125
+ items: SerializedContentItemWithType<Record<string, unknown>>[];
126
+ total: number;
127
+ limit: number;
128
+ offset: number;
129
+ }>;
130
+ getInverseRelations: better_call.StrictEndpoint<"/content-types/:slug/inverse-relations", {
131
+ method: "GET";
132
+ params: z.ZodObject<{
133
+ slug: z.ZodString;
134
+ }, z.core.$strip>;
135
+ query: z.ZodObject<{
136
+ itemId: z.ZodOptional<z.ZodString>;
137
+ }, z.core.$strip>;
138
+ }, {
139
+ inverseRelations: InverseRelation[];
140
+ }>;
141
+ listInverseRelationItems: better_call.StrictEndpoint<"/content-types/:slug/inverse-relations/:sourceType", {
142
+ method: "GET";
143
+ params: z.ZodObject<{
144
+ slug: z.ZodString;
145
+ sourceType: z.ZodString;
146
+ }, z.core.$strip>;
147
+ query: z.ZodObject<{
148
+ itemId: z.ZodString;
149
+ fieldName: z.ZodString;
150
+ limit: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
151
+ offset: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
152
+ }, z.core.$strip>;
153
+ }, {
154
+ items: SerializedContentItemWithType<Record<string, unknown>>[];
155
+ total: number;
156
+ limit: number;
157
+ offset: number;
158
+ }>;
95
159
  }>;
96
160
  type CMSApiRouter = ReturnType<ReturnType<typeof cmsBackendPlugin>["routes"]>;
97
161
 
@@ -5,13 +5,17 @@ const cmsHooks = require('../../../../packages/better-stack/src/plugins/cms/clie
5
5
 
6
6
 
7
7
  exports.useContent = cmsHooks.useContent;
8
+ exports.useContentByRelation = cmsHooks.useContentByRelation;
8
9
  exports.useContentItem = cmsHooks.useContentItem;
9
10
  exports.useContentItemBySlug = cmsHooks.useContentItemBySlug;
11
+ exports.useContentItemPopulated = cmsHooks.useContentItemPopulated;
10
12
  exports.useContentType = cmsHooks.useContentType;
11
13
  exports.useContentTypes = cmsHooks.useContentTypes;
12
14
  exports.useCreateContent = cmsHooks.useCreateContent;
13
15
  exports.useDeleteContent = cmsHooks.useDeleteContent;
14
16
  exports.useSuspenseContent = cmsHooks.useSuspenseContent;
17
+ exports.useSuspenseContentByRelation = cmsHooks.useSuspenseContentByRelation;
15
18
  exports.useSuspenseContentItem = cmsHooks.useSuspenseContentItem;
19
+ exports.useSuspenseContentItemPopulated = cmsHooks.useSuspenseContentItemPopulated;
16
20
  exports.useSuspenseContentTypes = cmsHooks.useSuspenseContentTypes;
17
21
  exports.useUpdateContent = cmsHooks.useUpdateContent;
@@ -1,5 +1,5 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { S as SerializedContentType, a as SerializedContentItemWithType } from '../../../../shared/stack.L-UFwz2G.cjs';
2
+ import { S as SerializedContentType, a as SerializedContentItemWithType } from '../../../../shared/stack.oGOteE6g.cjs';
3
3
  import 'zod';
4
4
 
5
5
  interface UseContentTypesResult {
@@ -195,6 +195,85 @@ declare function useUpdateContent<TData = Record<string, unknown>>(typeSlug: str
195
195
  declare function useDeleteContent(typeSlug: string): _tanstack_react_query.UseMutationResult<{
196
196
  success: boolean;
197
197
  }, Error, string, unknown>;
198
+ /**
199
+ * Content item with populated relations
200
+ */
201
+ interface ContentItemWithRelations<TData = Record<string, unknown>> extends SerializedContentItemWithType<TData> {
202
+ _relations?: Record<string, SerializedContentItemWithType[]>;
203
+ }
204
+ /**
205
+ * Hook for fetching a content item with its relations populated.
206
+ * Use this when you need to display related items alongside the main item.
207
+ *
208
+ * @template TMap - A type map of content type slugs to their data types
209
+ * @template TSlug - The content type slug (inferred from typeSlug parameter)
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * type MyCMSTypes = {
214
+ * resource: { name: string; categoryIds: Array<{ id: string }> }
215
+ * category: { name: string }
216
+ * }
217
+ * const { item } = useContentItemPopulated<MyCMSTypes, "resource">("resource", "some-id")
218
+ * // item?._relations?.categoryIds contains populated category items
219
+ * ```
220
+ */
221
+ declare function useContentItemPopulated<TMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TSlug extends keyof TMap = keyof TMap>(typeSlug: TSlug & string, id: string): {
222
+ item: ContentItemWithRelations<TMap[TSlug]> | null;
223
+ isLoading: boolean;
224
+ error: Error | null;
225
+ refetch: () => void;
226
+ };
227
+ /**
228
+ * Suspense variant of useContentItemPopulated
229
+ */
230
+ declare function useSuspenseContentItemPopulated<TMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TSlug extends keyof TMap = keyof TMap>(typeSlug: TSlug & string, id: string): {
231
+ item: ContentItemWithRelations<TMap[TSlug]> | null;
232
+ refetch: () => Promise<unknown>;
233
+ };
234
+ /**
235
+ * Options for useContentByRelation hook
236
+ */
237
+ interface UseContentByRelationOptions {
238
+ /** Number of items per page (default: 20) */
239
+ limit?: number;
240
+ /** Whether to enable the query (default: true) */
241
+ enabled?: boolean;
242
+ }
243
+ /**
244
+ * Hook for fetching content items that have a specific relation.
245
+ * Useful for "filter by category" functionality.
246
+ *
247
+ * @template TMap - A type map of content type slugs to their data types
248
+ * @template TSlug - The content type slug (inferred from typeSlug parameter)
249
+ *
250
+ * @example
251
+ * ```typescript
252
+ * // Get all resources in a specific category
253
+ * const { items } = useContentByRelation("resource", "categoryIds", categoryId)
254
+ * ```
255
+ */
256
+ declare function useContentByRelation<TMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TSlug extends keyof TMap = keyof TMap>(typeSlug: TSlug & string, fieldName: string, targetId: string, options?: UseContentByRelationOptions): {
257
+ items: SerializedContentItemWithType<TMap[TSlug]>[];
258
+ total: number;
259
+ isLoading: boolean;
260
+ error: Error | null;
261
+ loadMore: () => void;
262
+ hasMore: boolean;
263
+ isLoadingMore: boolean;
264
+ refetch: () => void;
265
+ };
266
+ /**
267
+ * Suspense variant of useContentByRelation
268
+ */
269
+ declare function useSuspenseContentByRelation<TMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TSlug extends keyof TMap = keyof TMap>(typeSlug: TSlug & string, fieldName: string, targetId: string, options?: UseContentByRelationOptions): {
270
+ items: SerializedContentItemWithType<TMap[TSlug]>[];
271
+ total: number;
272
+ loadMore: () => Promise<unknown>;
273
+ hasMore: boolean;
274
+ isLoadingMore: boolean;
275
+ refetch: () => Promise<unknown>;
276
+ };
198
277
 
199
- export { useContent, useContentItem, useContentItemBySlug, useContentType, useContentTypes, useCreateContent, useDeleteContent, useSuspenseContent, useSuspenseContentItem, useSuspenseContentTypes, useUpdateContent };
200
- export type { UseContentOptions, UseContentResult, UseContentTypesResult };
278
+ export { useContent, useContentByRelation, useContentItem, useContentItemBySlug, useContentItemPopulated, useContentType, useContentTypes, useCreateContent, useDeleteContent, useSuspenseContent, useSuspenseContentByRelation, useSuspenseContentItem, useSuspenseContentItemPopulated, useSuspenseContentTypes, useUpdateContent };
279
+ export type { ContentItemWithRelations, UseContentByRelationOptions, UseContentOptions, UseContentResult, UseContentTypesResult };
@@ -1,5 +1,5 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { S as SerializedContentType, a as SerializedContentItemWithType } from '../../../../shared/stack.L-UFwz2G.mjs';
2
+ import { S as SerializedContentType, a as SerializedContentItemWithType } from '../../../../shared/stack.oGOteE6g.mjs';
3
3
  import 'zod';
4
4
 
5
5
  interface UseContentTypesResult {
@@ -195,6 +195,85 @@ declare function useUpdateContent<TData = Record<string, unknown>>(typeSlug: str
195
195
  declare function useDeleteContent(typeSlug: string): _tanstack_react_query.UseMutationResult<{
196
196
  success: boolean;
197
197
  }, Error, string, unknown>;
198
+ /**
199
+ * Content item with populated relations
200
+ */
201
+ interface ContentItemWithRelations<TData = Record<string, unknown>> extends SerializedContentItemWithType<TData> {
202
+ _relations?: Record<string, SerializedContentItemWithType[]>;
203
+ }
204
+ /**
205
+ * Hook for fetching a content item with its relations populated.
206
+ * Use this when you need to display related items alongside the main item.
207
+ *
208
+ * @template TMap - A type map of content type slugs to their data types
209
+ * @template TSlug - The content type slug (inferred from typeSlug parameter)
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * type MyCMSTypes = {
214
+ * resource: { name: string; categoryIds: Array<{ id: string }> }
215
+ * category: { name: string }
216
+ * }
217
+ * const { item } = useContentItemPopulated<MyCMSTypes, "resource">("resource", "some-id")
218
+ * // item?._relations?.categoryIds contains populated category items
219
+ * ```
220
+ */
221
+ declare function useContentItemPopulated<TMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TSlug extends keyof TMap = keyof TMap>(typeSlug: TSlug & string, id: string): {
222
+ item: ContentItemWithRelations<TMap[TSlug]> | null;
223
+ isLoading: boolean;
224
+ error: Error | null;
225
+ refetch: () => void;
226
+ };
227
+ /**
228
+ * Suspense variant of useContentItemPopulated
229
+ */
230
+ declare function useSuspenseContentItemPopulated<TMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TSlug extends keyof TMap = keyof TMap>(typeSlug: TSlug & string, id: string): {
231
+ item: ContentItemWithRelations<TMap[TSlug]> | null;
232
+ refetch: () => Promise<unknown>;
233
+ };
234
+ /**
235
+ * Options for useContentByRelation hook
236
+ */
237
+ interface UseContentByRelationOptions {
238
+ /** Number of items per page (default: 20) */
239
+ limit?: number;
240
+ /** Whether to enable the query (default: true) */
241
+ enabled?: boolean;
242
+ }
243
+ /**
244
+ * Hook for fetching content items that have a specific relation.
245
+ * Useful for "filter by category" functionality.
246
+ *
247
+ * @template TMap - A type map of content type slugs to their data types
248
+ * @template TSlug - The content type slug (inferred from typeSlug parameter)
249
+ *
250
+ * @example
251
+ * ```typescript
252
+ * // Get all resources in a specific category
253
+ * const { items } = useContentByRelation("resource", "categoryIds", categoryId)
254
+ * ```
255
+ */
256
+ declare function useContentByRelation<TMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TSlug extends keyof TMap = keyof TMap>(typeSlug: TSlug & string, fieldName: string, targetId: string, options?: UseContentByRelationOptions): {
257
+ items: SerializedContentItemWithType<TMap[TSlug]>[];
258
+ total: number;
259
+ isLoading: boolean;
260
+ error: Error | null;
261
+ loadMore: () => void;
262
+ hasMore: boolean;
263
+ isLoadingMore: boolean;
264
+ refetch: () => void;
265
+ };
266
+ /**
267
+ * Suspense variant of useContentByRelation
268
+ */
269
+ declare function useSuspenseContentByRelation<TMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TSlug extends keyof TMap = keyof TMap>(typeSlug: TSlug & string, fieldName: string, targetId: string, options?: UseContentByRelationOptions): {
270
+ items: SerializedContentItemWithType<TMap[TSlug]>[];
271
+ total: number;
272
+ loadMore: () => Promise<unknown>;
273
+ hasMore: boolean;
274
+ isLoadingMore: boolean;
275
+ refetch: () => Promise<unknown>;
276
+ };
198
277
 
199
- export { useContent, useContentItem, useContentItemBySlug, useContentType, useContentTypes, useCreateContent, useDeleteContent, useSuspenseContent, useSuspenseContentItem, useSuspenseContentTypes, useUpdateContent };
200
- export type { UseContentOptions, UseContentResult, UseContentTypesResult };
278
+ export { useContent, useContentByRelation, useContentItem, useContentItemBySlug, useContentItemPopulated, useContentType, useContentTypes, useCreateContent, useDeleteContent, useSuspenseContent, useSuspenseContentByRelation, useSuspenseContentItem, useSuspenseContentItemPopulated, useSuspenseContentTypes, useUpdateContent };
279
+ export type { ContentItemWithRelations, UseContentByRelationOptions, UseContentOptions, UseContentResult, UseContentTypesResult };
@@ -1,5 +1,5 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { S as SerializedContentType, a as SerializedContentItemWithType } from '../../../../shared/stack.L-UFwz2G.js';
2
+ import { S as SerializedContentType, a as SerializedContentItemWithType } from '../../../../shared/stack.oGOteE6g.js';
3
3
  import 'zod';
4
4
 
5
5
  interface UseContentTypesResult {
@@ -195,6 +195,85 @@ declare function useUpdateContent<TData = Record<string, unknown>>(typeSlug: str
195
195
  declare function useDeleteContent(typeSlug: string): _tanstack_react_query.UseMutationResult<{
196
196
  success: boolean;
197
197
  }, Error, string, unknown>;
198
+ /**
199
+ * Content item with populated relations
200
+ */
201
+ interface ContentItemWithRelations<TData = Record<string, unknown>> extends SerializedContentItemWithType<TData> {
202
+ _relations?: Record<string, SerializedContentItemWithType[]>;
203
+ }
204
+ /**
205
+ * Hook for fetching a content item with its relations populated.
206
+ * Use this when you need to display related items alongside the main item.
207
+ *
208
+ * @template TMap - A type map of content type slugs to their data types
209
+ * @template TSlug - The content type slug (inferred from typeSlug parameter)
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * type MyCMSTypes = {
214
+ * resource: { name: string; categoryIds: Array<{ id: string }> }
215
+ * category: { name: string }
216
+ * }
217
+ * const { item } = useContentItemPopulated<MyCMSTypes, "resource">("resource", "some-id")
218
+ * // item?._relations?.categoryIds contains populated category items
219
+ * ```
220
+ */
221
+ declare function useContentItemPopulated<TMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TSlug extends keyof TMap = keyof TMap>(typeSlug: TSlug & string, id: string): {
222
+ item: ContentItemWithRelations<TMap[TSlug]> | null;
223
+ isLoading: boolean;
224
+ error: Error | null;
225
+ refetch: () => void;
226
+ };
227
+ /**
228
+ * Suspense variant of useContentItemPopulated
229
+ */
230
+ declare function useSuspenseContentItemPopulated<TMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TSlug extends keyof TMap = keyof TMap>(typeSlug: TSlug & string, id: string): {
231
+ item: ContentItemWithRelations<TMap[TSlug]> | null;
232
+ refetch: () => Promise<unknown>;
233
+ };
234
+ /**
235
+ * Options for useContentByRelation hook
236
+ */
237
+ interface UseContentByRelationOptions {
238
+ /** Number of items per page (default: 20) */
239
+ limit?: number;
240
+ /** Whether to enable the query (default: true) */
241
+ enabled?: boolean;
242
+ }
243
+ /**
244
+ * Hook for fetching content items that have a specific relation.
245
+ * Useful for "filter by category" functionality.
246
+ *
247
+ * @template TMap - A type map of content type slugs to their data types
248
+ * @template TSlug - The content type slug (inferred from typeSlug parameter)
249
+ *
250
+ * @example
251
+ * ```typescript
252
+ * // Get all resources in a specific category
253
+ * const { items } = useContentByRelation("resource", "categoryIds", categoryId)
254
+ * ```
255
+ */
256
+ declare function useContentByRelation<TMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TSlug extends keyof TMap = keyof TMap>(typeSlug: TSlug & string, fieldName: string, targetId: string, options?: UseContentByRelationOptions): {
257
+ items: SerializedContentItemWithType<TMap[TSlug]>[];
258
+ total: number;
259
+ isLoading: boolean;
260
+ error: Error | null;
261
+ loadMore: () => void;
262
+ hasMore: boolean;
263
+ isLoadingMore: boolean;
264
+ refetch: () => void;
265
+ };
266
+ /**
267
+ * Suspense variant of useContentByRelation
268
+ */
269
+ declare function useSuspenseContentByRelation<TMap extends Record<string, Record<string, unknown>> = Record<string, Record<string, unknown>>, TSlug extends keyof TMap = keyof TMap>(typeSlug: TSlug & string, fieldName: string, targetId: string, options?: UseContentByRelationOptions): {
270
+ items: SerializedContentItemWithType<TMap[TSlug]>[];
271
+ total: number;
272
+ loadMore: () => Promise<unknown>;
273
+ hasMore: boolean;
274
+ isLoadingMore: boolean;
275
+ refetch: () => Promise<unknown>;
276
+ };
198
277
 
199
- export { useContent, useContentItem, useContentItemBySlug, useContentType, useContentTypes, useCreateContent, useDeleteContent, useSuspenseContent, useSuspenseContentItem, useSuspenseContentTypes, useUpdateContent };
200
- export type { UseContentOptions, UseContentResult, UseContentTypesResult };
278
+ export { useContent, useContentByRelation, useContentItem, useContentItemBySlug, useContentItemPopulated, useContentType, useContentTypes, useCreateContent, useDeleteContent, useSuspenseContent, useSuspenseContentByRelation, useSuspenseContentItem, useSuspenseContentItemPopulated, useSuspenseContentTypes, useUpdateContent };
279
+ export type { ContentItemWithRelations, UseContentByRelationOptions, UseContentOptions, UseContentResult, UseContentTypesResult };
@@ -1 +1 @@
1
- export { useContent, useContentItem, useContentItemBySlug, useContentType, useContentTypes, useCreateContent, useDeleteContent, useSuspenseContent, useSuspenseContentItem, useSuspenseContentTypes, useUpdateContent } from '../../../../packages/better-stack/src/plugins/cms/client/hooks/cms-hooks.mjs';
1
+ export { useContent, useContentByRelation, useContentItem, useContentItemBySlug, useContentItemPopulated, useContentType, useContentTypes, useCreateContent, useDeleteContent, useSuspenseContent, useSuspenseContentByRelation, useSuspenseContentItem, useSuspenseContentItemPopulated, useSuspenseContentTypes, useUpdateContent } from '../../../../packages/better-stack/src/plugins/cms/client/hooks/cms-hooks.mjs';
@@ -1,6 +1,6 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
2
  import { createApiClient } from '@btst/stack/plugins/client';
3
- import { S as SerializedContentType, P as PaginatedContentItems, a as SerializedContentItemWithType } from '../../shared/stack.L-UFwz2G.cjs';
3
+ import { S as SerializedContentType, P as PaginatedContentItems, a as SerializedContentItemWithType } from '../../shared/stack.oGOteE6g.cjs';
4
4
  import { CMSApiRouter } from './api/index.cjs';
5
5
  import 'zod';
6
6
  import '@btst/stack/plugins/api';
@@ -1,6 +1,6 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
2
  import { createApiClient } from '@btst/stack/plugins/client';
3
- import { S as SerializedContentType, P as PaginatedContentItems, a as SerializedContentItemWithType } from '../../shared/stack.L-UFwz2G.mjs';
3
+ import { S as SerializedContentType, P as PaginatedContentItems, a as SerializedContentItemWithType } from '../../shared/stack.oGOteE6g.mjs';
4
4
  import { CMSApiRouter } from './api/index.mjs';
5
5
  import 'zod';
6
6
  import '@btst/stack/plugins/api';
@@ -1,6 +1,6 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
2
  import { createApiClient } from '@btst/stack/plugins/client';
3
- import { S as SerializedContentType, P as PaginatedContentItems, a as SerializedContentItemWithType } from '../../shared/stack.L-UFwz2G.js';
3
+ import { S as SerializedContentType, P as PaginatedContentItems, a as SerializedContentItemWithType } from '../../shared/stack.oGOteE6g.js';
4
4
  import { CMSApiRouter } from './api/index.js';
5
5
  import 'zod';
6
6
  import '@btst/stack/plugins/api';