@btst/stack 1.8.0 → 1.9.1

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 (94) 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 +28 -11
  4. package/dist/packages/better-stack/src/plugins/cms/client/components/forms/content-form.mjs +26 -9
  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/better-stack/src/plugins/form-builder/client/components/forms/form-renderer.cjs +2 -2
  16. package/dist/packages/better-stack/src/plugins/form-builder/client/components/forms/form-renderer.mjs +1 -1
  17. package/dist/packages/ui/src/components/auto-form/fields/array.cjs +2 -2
  18. package/dist/packages/ui/src/components/auto-form/fields/array.mjs +1 -1
  19. package/dist/packages/ui/src/components/auto-form/fields/date.cjs +2 -2
  20. package/dist/packages/ui/src/components/auto-form/fields/date.mjs +1 -1
  21. package/dist/packages/ui/src/components/auto-form/fields/enum.cjs +2 -2
  22. package/dist/packages/ui/src/components/auto-form/fields/enum.mjs +1 -1
  23. package/dist/packages/ui/src/components/auto-form/fields/object.cjs +88 -8
  24. package/dist/packages/ui/src/components/auto-form/fields/object.mjs +82 -2
  25. package/dist/packages/ui/src/components/auto-form/fields/radio-group.cjs +2 -2
  26. package/dist/packages/ui/src/components/auto-form/fields/radio-group.mjs +1 -1
  27. package/dist/packages/ui/src/components/auto-form/index.cjs +5 -5
  28. package/dist/packages/ui/src/components/auto-form/index.mjs +1 -1
  29. package/dist/packages/ui/src/components/button.cjs +4 -2
  30. package/dist/packages/ui/src/components/button.mjs +4 -2
  31. package/dist/packages/ui/src/components/dialog.cjs +7 -1
  32. package/dist/packages/ui/src/components/dialog.mjs +7 -2
  33. package/dist/packages/ui/src/components/form-builder/edit-field-dialog.cjs +2 -2
  34. package/dist/packages/ui/src/components/form-builder/edit-field-dialog.mjs +1 -1
  35. package/dist/packages/ui/src/components/form-builder/form-preview.cjs +5 -5
  36. package/dist/packages/ui/src/components/form-builder/form-preview.mjs +1 -1
  37. package/dist/packages/ui/src/components/select.cjs +9 -2
  38. package/dist/packages/ui/src/components/select.mjs +9 -2
  39. package/dist/plugins/blog/api/index.d.cts +1 -1
  40. package/dist/plugins/blog/api/index.d.mts +1 -1
  41. package/dist/plugins/blog/api/index.d.ts +1 -1
  42. package/dist/plugins/blog/client/hooks/index.d.cts +2 -2
  43. package/dist/plugins/blog/client/hooks/index.d.mts +2 -2
  44. package/dist/plugins/blog/client/hooks/index.d.ts +2 -2
  45. package/dist/plugins/blog/client/index.d.cts +1 -1
  46. package/dist/plugins/blog/client/index.d.mts +1 -1
  47. package/dist/plugins/blog/client/index.d.ts +1 -1
  48. package/dist/plugins/blog/query-keys.d.cts +2 -2
  49. package/dist/plugins/blog/query-keys.d.mts +2 -2
  50. package/dist/plugins/blog/query-keys.d.ts +2 -2
  51. package/dist/plugins/cms/api/index.d.cts +66 -2
  52. package/dist/plugins/cms/api/index.d.mts +66 -2
  53. package/dist/plugins/cms/api/index.d.ts +66 -2
  54. package/dist/plugins/cms/client/hooks/index.cjs +4 -0
  55. package/dist/plugins/cms/client/hooks/index.d.cts +82 -3
  56. package/dist/plugins/cms/client/hooks/index.d.mts +82 -3
  57. package/dist/plugins/cms/client/hooks/index.d.ts +82 -3
  58. package/dist/plugins/cms/client/hooks/index.mjs +1 -1
  59. package/dist/plugins/cms/client/index.d.cts +2 -2
  60. package/dist/plugins/cms/client/index.d.mts +2 -2
  61. package/dist/plugins/cms/client/index.d.ts +2 -2
  62. package/dist/plugins/cms/query-keys.d.cts +1 -1
  63. package/dist/plugins/cms/query-keys.d.mts +1 -1
  64. package/dist/plugins/cms/query-keys.d.ts +1 -1
  65. package/dist/plugins/form-builder/client/components/index.d.cts +1 -1
  66. package/dist/plugins/form-builder/client/components/index.d.mts +1 -1
  67. package/dist/plugins/form-builder/client/components/index.d.ts +1 -1
  68. package/dist/plugins/form-builder/client/index.d.cts +2 -2
  69. package/dist/plugins/form-builder/client/index.d.mts +2 -2
  70. package/dist/plugins/form-builder/client/index.d.ts +2 -2
  71. package/dist/shared/{stack.AX5nZ6A3.d.ts → stack.Co034Fpm.d.cts} +0 -21
  72. package/dist/shared/{stack.AX5nZ6A3.d.cts → stack.Co034Fpm.d.mts} +0 -21
  73. package/dist/shared/{stack.AX5nZ6A3.d.mts → stack.Co034Fpm.d.ts} +0 -21
  74. package/dist/shared/{stack.BIh2AXaW.d.cts → stack.DGjhPqmF.d.cts} +0 -9
  75. package/dist/shared/{stack.BIh2AXaW.d.mts → stack.DGjhPqmF.d.mts} +0 -9
  76. package/dist/shared/{stack.BIh2AXaW.d.ts → stack.DGjhPqmF.d.ts} +0 -9
  77. package/dist/shared/{stack.L-UFwz2G.d.mts → stack.oGOteE6g.d.cts} +27 -5
  78. package/dist/shared/{stack.L-UFwz2G.d.cts → stack.oGOteE6g.d.mts} +27 -5
  79. package/dist/shared/{stack.L-UFwz2G.d.ts → stack.oGOteE6g.d.ts} +27 -5
  80. package/package.json +1 -1
  81. package/src/plugins/cms/api/plugin.ts +667 -21
  82. package/src/plugins/cms/client/components/forms/content-form.tsx +62 -20
  83. package/src/plugins/cms/client/components/forms/relation-field.tsx +299 -0
  84. package/src/plugins/cms/client/components/inverse-relations-panel.tsx +329 -0
  85. package/src/plugins/cms/client/components/pages/content-editor-page.internal.tsx +127 -1
  86. package/src/plugins/cms/client/hooks/cms-hooks.tsx +344 -0
  87. package/src/plugins/cms/db.ts +38 -0
  88. package/src/plugins/cms/types.ts +99 -10
  89. package/src/plugins/form-builder/client/components/forms/form-renderer.tsx +1 -1
  90. package/dist/packages/ui/src/components/auto-form/{utils.cjs → helpers.cjs} +0 -0
  91. package/dist/packages/ui/src/components/auto-form/{utils.mjs → helpers.mjs} +0 -0
  92. package/dist/shared/{stack.DLhzx1-D.d.mts → stack.CcI4sYJP.d.cts} +1 -1
  93. package/dist/shared/{stack.DLhzx1-D.d.cts → stack.CcI4sYJP.d.mts} +1 -1
  94. package/dist/shared/{stack.DLhzx1-D.d.ts → stack.CcI4sYJP.d.ts} +1 -1
@@ -3,8 +3,8 @@ import * as react from 'react';
3
3
  import { ComponentType } from 'react';
4
4
  import * as _btst_yar from '@btst/yar';
5
5
  import { QueryClient } from '@tanstack/react-query';
6
- import { A as AutoFormInputComponentProps } from '../../../shared/stack.BIh2AXaW.cjs';
7
- export { b as FormSchemaMetadata, F as FormStep, f as formSchemaToZod, a as getStepGroupMap, g as getSteps, h as hasSteps, z as zodToFormSchema } from '../../../shared/stack.AX5nZ6A3.cjs';
6
+ import { A as AutoFormInputComponentProps } from '../../../shared/stack.DGjhPqmF.cjs';
7
+ export { b as FormSchemaMetadata, F as FormStep, f as formSchemaToZod, a as getStepGroupMap, g as getSteps, h as hasSteps, z as zodToFormSchema } from '../../../shared/stack.Co034Fpm.cjs';
8
8
  import * as react_jsx_runtime from 'react/jsx-runtime';
9
9
  import 'react-hook-form';
10
10
  import 'zod';
@@ -3,8 +3,8 @@ import * as react from 'react';
3
3
  import { ComponentType } from 'react';
4
4
  import * as _btst_yar from '@btst/yar';
5
5
  import { QueryClient } from '@tanstack/react-query';
6
- import { A as AutoFormInputComponentProps } from '../../../shared/stack.BIh2AXaW.mjs';
7
- export { b as FormSchemaMetadata, F as FormStep, f as formSchemaToZod, a as getStepGroupMap, g as getSteps, h as hasSteps, z as zodToFormSchema } from '../../../shared/stack.AX5nZ6A3.mjs';
6
+ import { A as AutoFormInputComponentProps } from '../../../shared/stack.DGjhPqmF.mjs';
7
+ export { b as FormSchemaMetadata, F as FormStep, f as formSchemaToZod, a as getStepGroupMap, g as getSteps, h as hasSteps, z as zodToFormSchema } from '../../../shared/stack.Co034Fpm.mjs';
8
8
  import * as react_jsx_runtime from 'react/jsx-runtime';
9
9
  import 'react-hook-form';
10
10
  import 'zod';
@@ -3,8 +3,8 @@ import * as react from 'react';
3
3
  import { ComponentType } from 'react';
4
4
  import * as _btst_yar from '@btst/yar';
5
5
  import { QueryClient } from '@tanstack/react-query';
6
- import { A as AutoFormInputComponentProps } from '../../../shared/stack.BIh2AXaW.js';
7
- export { b as FormSchemaMetadata, F as FormStep, f as formSchemaToZod, a as getStepGroupMap, g as getSteps, h as hasSteps, z as zodToFormSchema } from '../../../shared/stack.AX5nZ6A3.js';
6
+ import { A as AutoFormInputComponentProps } from '../../../shared/stack.DGjhPqmF.js';
7
+ export { b as FormSchemaMetadata, F as FormStep, f as formSchemaToZod, a as getStepGroupMap, g as getSteps, h as hasSteps, z as zodToFormSchema } from '../../../shared/stack.Co034Fpm.js';
8
8
  import * as react_jsx_runtime from 'react/jsx-runtime';
9
9
  import 'react-hook-form';
10
10
  import 'zod';
@@ -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';
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ComponentType } from 'react';
3
- import { A as AutoFormInputComponentProps } from '../../../../shared/stack.BIh2AXaW.cjs';
3
+ import { A as AutoFormInputComponentProps } from '../../../../shared/stack.DGjhPqmF.cjs';
4
4
  import { a as SerializedFormSubmission } from '../../../../shared/stack.DzH_wcvr.cjs';
5
5
  import 'react-hook-form';
6
6
  import 'zod';
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ComponentType } from 'react';
3
- import { A as AutoFormInputComponentProps } from '../../../../shared/stack.BIh2AXaW.mjs';
3
+ import { A as AutoFormInputComponentProps } from '../../../../shared/stack.DGjhPqmF.mjs';
4
4
  import { a as SerializedFormSubmission } from '../../../../shared/stack.DzH_wcvr.mjs';
5
5
  import 'react-hook-form';
6
6
  import 'zod';
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ComponentType } from 'react';
3
- import { A as AutoFormInputComponentProps } from '../../../../shared/stack.BIh2AXaW.js';
3
+ import { A as AutoFormInputComponentProps } from '../../../../shared/stack.DGjhPqmF.js';
4
4
  import { a as SerializedFormSubmission } from '../../../../shared/stack.DzH_wcvr.js';
5
5
  import 'react-hook-form';
6
6
  import 'zod';
@@ -3,8 +3,8 @@ import * as react from 'react';
3
3
  import { ComponentType } from 'react';
4
4
  import * as _btst_yar from '@btst/yar';
5
5
  import { QueryClient } from '@tanstack/react-query';
6
- import { A as AutoFormInputComponentProps } from '../../../shared/stack.BIh2AXaW.cjs';
7
- export { b as FormSchemaMetadata, F as FormStep, f as formSchemaToZod, a as getStepGroupMap, g as getSteps, h as hasSteps, z as zodToFormSchema } from '../../../shared/stack.AX5nZ6A3.cjs';
6
+ import { A as AutoFormInputComponentProps } from '../../../shared/stack.DGjhPqmF.cjs';
7
+ export { b as FormSchemaMetadata, F as FormStep, f as formSchemaToZod, a as getStepGroupMap, g as getSteps, h as hasSteps, z as zodToFormSchema } from '../../../shared/stack.Co034Fpm.cjs';
8
8
  import 'react-hook-form';
9
9
  import 'zod';
10
10
  import 'react/jsx-runtime';
@@ -3,8 +3,8 @@ import * as react from 'react';
3
3
  import { ComponentType } from 'react';
4
4
  import * as _btst_yar from '@btst/yar';
5
5
  import { QueryClient } from '@tanstack/react-query';
6
- import { A as AutoFormInputComponentProps } from '../../../shared/stack.BIh2AXaW.mjs';
7
- export { b as FormSchemaMetadata, F as FormStep, f as formSchemaToZod, a as getStepGroupMap, g as getSteps, h as hasSteps, z as zodToFormSchema } from '../../../shared/stack.AX5nZ6A3.mjs';
6
+ import { A as AutoFormInputComponentProps } from '../../../shared/stack.DGjhPqmF.mjs';
7
+ export { b as FormSchemaMetadata, F as FormStep, f as formSchemaToZod, a as getStepGroupMap, g as getSteps, h as hasSteps, z as zodToFormSchema } from '../../../shared/stack.Co034Fpm.mjs';
8
8
  import 'react-hook-form';
9
9
  import 'zod';
10
10
  import 'react/jsx-runtime';
@@ -3,8 +3,8 @@ import * as react from 'react';
3
3
  import { ComponentType } from 'react';
4
4
  import * as _btst_yar from '@btst/yar';
5
5
  import { QueryClient } from '@tanstack/react-query';
6
- import { A as AutoFormInputComponentProps } from '../../../shared/stack.BIh2AXaW.js';
7
- export { b as FormSchemaMetadata, F as FormStep, f as formSchemaToZod, a as getStepGroupMap, g as getSteps, h as hasSteps, z as zodToFormSchema } from '../../../shared/stack.AX5nZ6A3.js';
6
+ import { A as AutoFormInputComponentProps } from '../../../shared/stack.DGjhPqmF.js';
7
+ export { b as FormSchemaMetadata, F as FormStep, f as formSchemaToZod, a as getStepGroupMap, g as getSteps, h as hasSteps, z as zodToFormSchema } from '../../../shared/stack.Co034Fpm.js';
8
8
  import 'react-hook-form';
9
9
  import 'zod';
10
10
  import 'react/jsx-runtime';
@@ -1,26 +1,5 @@
1
1
  import { z } from 'zod';
2
2
 
3
- /**
4
- * Unified Schema Converter Module
5
- *
6
- * Provides consistent bidirectional conversion between Zod schemas and JSON Schema,
7
- * handling all edge cases in one place:
8
- *
9
- * 1. Date handling: z.date() ↔ { type: "string", format: "date-time" }
10
- * 2. Steps metadata: Preserves multi-step form configuration
11
- * 3. Step group mapping: Tracks which fields belong to which step
12
- * 4. Date constraints: Preserves min/max date validations
13
- *
14
- * Usage:
15
- * ```ts
16
- * // Zod → JSON Schema (for storage/transport)
17
- * const jsonSchema = zodToFormSchema(myZodSchema);
18
- *
19
- * // JSON Schema → Zod (for validation)
20
- * const zodSchema = formSchemaToZod(jsonSchema);
21
- * ```
22
- */
23
-
24
3
  interface FormStep {
25
4
  id: string;
26
5
  title: string;
@@ -1,26 +1,5 @@
1
1
  import { z } from 'zod';
2
2
 
3
- /**
4
- * Unified Schema Converter Module
5
- *
6
- * Provides consistent bidirectional conversion between Zod schemas and JSON Schema,
7
- * handling all edge cases in one place:
8
- *
9
- * 1. Date handling: z.date() ↔ { type: "string", format: "date-time" }
10
- * 2. Steps metadata: Preserves multi-step form configuration
11
- * 3. Step group mapping: Tracks which fields belong to which step
12
- * 4. Date constraints: Preserves min/max date validations
13
- *
14
- * Usage:
15
- * ```ts
16
- * // Zod → JSON Schema (for storage/transport)
17
- * const jsonSchema = zodToFormSchema(myZodSchema);
18
- *
19
- * // JSON Schema → Zod (for validation)
20
- * const zodSchema = formSchemaToZod(jsonSchema);
21
- * ```
22
- */
23
-
24
3
  interface FormStep {
25
4
  id: string;
26
5
  title: string;
@@ -1,26 +1,5 @@
1
1
  import { z } from 'zod';
2
2
 
3
- /**
4
- * Unified Schema Converter Module
5
- *
6
- * Provides consistent bidirectional conversion between Zod schemas and JSON Schema,
7
- * handling all edge cases in one place:
8
- *
9
- * 1. Date handling: z.date() ↔ { type: "string", format: "date-time" }
10
- * 2. Steps metadata: Preserves multi-step form configuration
11
- * 3. Step group mapping: Tracks which fields belong to which step
12
- * 4. Date constraints: Preserves min/max date validations
13
- *
14
- * Usage:
15
- * ```ts
16
- * // Zod → JSON Schema (for storage/transport)
17
- * const jsonSchema = zodToFormSchema(myZodSchema);
18
- *
19
- * // JSON Schema → Zod (for validation)
20
- * const zodSchema = formSchemaToZod(jsonSchema);
21
- * ```
22
- */
23
-
24
3
  interface FormStep {
25
4
  id: string;
26
5
  title: string;
@@ -29,15 +29,6 @@ declare const INPUT_COMPONENTS: {
29
29
  fallback: typeof AutoFormInput;
30
30
  };
31
31
 
32
- /**
33
- * Shared types between form-builder and auto-form.
34
- *
35
- * These types ensure consistency when:
36
- * - form-builder creates JSON Schema properties
37
- * - auto-form consumes JSON Schema properties
38
- * - inputProps flow from form-builder → JSON Schema → auto-form
39
- */
40
-
41
32
  /**
42
33
  * Common input props shared by all field types.
43
34
  */
@@ -29,15 +29,6 @@ declare const INPUT_COMPONENTS: {
29
29
  fallback: typeof AutoFormInput;
30
30
  };
31
31
 
32
- /**
33
- * Shared types between form-builder and auto-form.
34
- *
35
- * These types ensure consistency when:
36
- * - form-builder creates JSON Schema properties
37
- * - auto-form consumes JSON Schema properties
38
- * - inputProps flow from form-builder → JSON Schema → auto-form
39
- */
40
-
41
32
  /**
42
33
  * Common input props shared by all field types.
43
34
  */
@@ -29,15 +29,6 @@ declare const INPUT_COMPONENTS: {
29
29
  fallback: typeof AutoFormInput;
30
30
  };
31
31
 
32
- /**
33
- * Shared types between form-builder and auto-form.
34
- *
35
- * These types ensure consistency when:
36
- * - form-builder creates JSON Schema properties
37
- * - auto-form consumes JSON Schema properties
38
- * - inputProps flow from form-builder → JSON Schema → auto-form
39
- */
40
-
41
32
  /**
42
33
  * Common input props shared by all field types.
43
34
  */
@@ -58,6 +58,19 @@ type ContentItem = {
58
58
  createdAt: Date;
59
59
  updatedAt: Date;
60
60
  };
61
+ /**
62
+ * Represents an inverse relation (content types that reference this type via belongsTo)
63
+ */
64
+ interface InverseRelation {
65
+ /** The content type slug that has the belongsTo relation */
66
+ sourceType: string;
67
+ /** Display name of the source content type */
68
+ sourceTypeName: string;
69
+ /** The field name that contains the belongsTo relation */
70
+ fieldName: string;
71
+ /** Count of items with this relation (when itemId is provided) */
72
+ count: number;
73
+ }
61
74
  /**
62
75
  * Serialized content type for API responses (dates as strings)
63
76
  */
@@ -81,6 +94,11 @@ interface SerializedContentItemWithType<TData = Record<string, unknown>> extends
81
94
  parsedData: TData;
82
95
  /** Joined content type */
83
96
  contentType?: SerializedContentType;
97
+ /**
98
+ * Populated relation data (only present when using populated endpoints/hooks).
99
+ * Keys are field names, values are arrays of related content items.
100
+ */
101
+ _relations?: Record<string, SerializedContentItemWithType[]>;
84
102
  }
85
103
  /**
86
104
  * Paginated list response for content items
@@ -105,14 +123,18 @@ interface CMSHookContext {
105
123
  }
106
124
  /**
107
125
  * Hooks for customizing CMS backend behavior
126
+ *
127
+ * Note: Before hooks can only deny operations by returning `false`.
128
+ * They cannot modify the data being saved. This ensures consistency
129
+ * between the stored content item data and relation junction tables.
108
130
  */
109
131
  interface CMSBackendHooks {
110
- /** Called before creating a content item */
111
- onBeforeCreate?: (data: Record<string, unknown>, context: CMSHookContext) => Promise<Record<string, unknown> | false> | Record<string, unknown> | false;
132
+ /** Called before creating a content item. Return false to deny the operation. */
133
+ onBeforeCreate?: (data: Record<string, unknown>, context: CMSHookContext) => Promise<false | void> | false | void;
112
134
  /** Called after creating a content item */
113
135
  onAfterCreate?: (item: SerializedContentItem, context: CMSHookContext) => Promise<void> | void;
114
- /** Called before updating a content item */
115
- onBeforeUpdate?: (id: string, data: Record<string, unknown>, context: CMSHookContext) => Promise<Record<string, unknown> | false> | Record<string, unknown> | false;
136
+ /** Called before updating a content item. Return false to deny the operation. */
137
+ onBeforeUpdate?: (id: string, data: Record<string, unknown>, context: CMSHookContext) => Promise<false | void> | false | void;
116
138
  /** Called after updating a content item */
117
139
  onAfterUpdate?: (item: SerializedContentItem, context: CMSHookContext) => Promise<void> | void;
118
140
  /** Called before deleting a content item */
@@ -132,4 +154,4 @@ interface CMSBackendConfig {
132
154
  hooks?: CMSBackendHooks;
133
155
  }
134
156
 
135
- export type { CMSBackendConfig as C, PaginatedContentItems as P, SerializedContentType as S, SerializedContentItemWithType as a };
157
+ export type { CMSBackendConfig as C, InverseRelation as I, PaginatedContentItems as P, SerializedContentType as S, SerializedContentItemWithType as a };
@@ -58,6 +58,19 @@ type ContentItem = {
58
58
  createdAt: Date;
59
59
  updatedAt: Date;
60
60
  };
61
+ /**
62
+ * Represents an inverse relation (content types that reference this type via belongsTo)
63
+ */
64
+ interface InverseRelation {
65
+ /** The content type slug that has the belongsTo relation */
66
+ sourceType: string;
67
+ /** Display name of the source content type */
68
+ sourceTypeName: string;
69
+ /** The field name that contains the belongsTo relation */
70
+ fieldName: string;
71
+ /** Count of items with this relation (when itemId is provided) */
72
+ count: number;
73
+ }
61
74
  /**
62
75
  * Serialized content type for API responses (dates as strings)
63
76
  */
@@ -81,6 +94,11 @@ interface SerializedContentItemWithType<TData = Record<string, unknown>> extends
81
94
  parsedData: TData;
82
95
  /** Joined content type */
83
96
  contentType?: SerializedContentType;
97
+ /**
98
+ * Populated relation data (only present when using populated endpoints/hooks).
99
+ * Keys are field names, values are arrays of related content items.
100
+ */
101
+ _relations?: Record<string, SerializedContentItemWithType[]>;
84
102
  }
85
103
  /**
86
104
  * Paginated list response for content items
@@ -105,14 +123,18 @@ interface CMSHookContext {
105
123
  }
106
124
  /**
107
125
  * Hooks for customizing CMS backend behavior
126
+ *
127
+ * Note: Before hooks can only deny operations by returning `false`.
128
+ * They cannot modify the data being saved. This ensures consistency
129
+ * between the stored content item data and relation junction tables.
108
130
  */
109
131
  interface CMSBackendHooks {
110
- /** Called before creating a content item */
111
- onBeforeCreate?: (data: Record<string, unknown>, context: CMSHookContext) => Promise<Record<string, unknown> | false> | Record<string, unknown> | false;
132
+ /** Called before creating a content item. Return false to deny the operation. */
133
+ onBeforeCreate?: (data: Record<string, unknown>, context: CMSHookContext) => Promise<false | void> | false | void;
112
134
  /** Called after creating a content item */
113
135
  onAfterCreate?: (item: SerializedContentItem, context: CMSHookContext) => Promise<void> | void;
114
- /** Called before updating a content item */
115
- onBeforeUpdate?: (id: string, data: Record<string, unknown>, context: CMSHookContext) => Promise<Record<string, unknown> | false> | Record<string, unknown> | false;
136
+ /** Called before updating a content item. Return false to deny the operation. */
137
+ onBeforeUpdate?: (id: string, data: Record<string, unknown>, context: CMSHookContext) => Promise<false | void> | false | void;
116
138
  /** Called after updating a content item */
117
139
  onAfterUpdate?: (item: SerializedContentItem, context: CMSHookContext) => Promise<void> | void;
118
140
  /** Called before deleting a content item */
@@ -132,4 +154,4 @@ interface CMSBackendConfig {
132
154
  hooks?: CMSBackendHooks;
133
155
  }
134
156
 
135
- export type { CMSBackendConfig as C, PaginatedContentItems as P, SerializedContentType as S, SerializedContentItemWithType as a };
157
+ export type { CMSBackendConfig as C, InverseRelation as I, PaginatedContentItems as P, SerializedContentType as S, SerializedContentItemWithType as a };
@@ -58,6 +58,19 @@ type ContentItem = {
58
58
  createdAt: Date;
59
59
  updatedAt: Date;
60
60
  };
61
+ /**
62
+ * Represents an inverse relation (content types that reference this type via belongsTo)
63
+ */
64
+ interface InverseRelation {
65
+ /** The content type slug that has the belongsTo relation */
66
+ sourceType: string;
67
+ /** Display name of the source content type */
68
+ sourceTypeName: string;
69
+ /** The field name that contains the belongsTo relation */
70
+ fieldName: string;
71
+ /** Count of items with this relation (when itemId is provided) */
72
+ count: number;
73
+ }
61
74
  /**
62
75
  * Serialized content type for API responses (dates as strings)
63
76
  */
@@ -81,6 +94,11 @@ interface SerializedContentItemWithType<TData = Record<string, unknown>> extends
81
94
  parsedData: TData;
82
95
  /** Joined content type */
83
96
  contentType?: SerializedContentType;
97
+ /**
98
+ * Populated relation data (only present when using populated endpoints/hooks).
99
+ * Keys are field names, values are arrays of related content items.
100
+ */
101
+ _relations?: Record<string, SerializedContentItemWithType[]>;
84
102
  }
85
103
  /**
86
104
  * Paginated list response for content items
@@ -105,14 +123,18 @@ interface CMSHookContext {
105
123
  }
106
124
  /**
107
125
  * Hooks for customizing CMS backend behavior
126
+ *
127
+ * Note: Before hooks can only deny operations by returning `false`.
128
+ * They cannot modify the data being saved. This ensures consistency
129
+ * between the stored content item data and relation junction tables.
108
130
  */
109
131
  interface CMSBackendHooks {
110
- /** Called before creating a content item */
111
- onBeforeCreate?: (data: Record<string, unknown>, context: CMSHookContext) => Promise<Record<string, unknown> | false> | Record<string, unknown> | false;
132
+ /** Called before creating a content item. Return false to deny the operation. */
133
+ onBeforeCreate?: (data: Record<string, unknown>, context: CMSHookContext) => Promise<false | void> | false | void;
112
134
  /** Called after creating a content item */
113
135
  onAfterCreate?: (item: SerializedContentItem, context: CMSHookContext) => Promise<void> | void;
114
- /** Called before updating a content item */
115
- onBeforeUpdate?: (id: string, data: Record<string, unknown>, context: CMSHookContext) => Promise<Record<string, unknown> | false> | Record<string, unknown> | false;
136
+ /** Called before updating a content item. Return false to deny the operation. */
137
+ onBeforeUpdate?: (id: string, data: Record<string, unknown>, context: CMSHookContext) => Promise<false | void> | false | void;
116
138
  /** Called after updating a content item */
117
139
  onAfterUpdate?: (item: SerializedContentItem, context: CMSHookContext) => Promise<void> | void;
118
140
  /** Called before deleting a content item */
@@ -132,4 +154,4 @@ interface CMSBackendConfig {
132
154
  hooks?: CMSBackendHooks;
133
155
  }
134
156
 
135
- export type { CMSBackendConfig as C, PaginatedContentItems as P, SerializedContentType as S, SerializedContentItemWithType as a };
157
+ export type { CMSBackendConfig as C, InverseRelation as I, PaginatedContentItems as P, SerializedContentType as S, SerializedContentItemWithType as a };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@btst/stack",
3
- "version": "1.8.0",
3
+ "version": "1.9.1",
4
4
  "description": "A composable, plugin-based library for building full-stack applications.",
5
5
  "repository": {
6
6
  "type": "git",