@btst/stack 1.5.2 → 1.6.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 (201) hide show
  1. package/dist/node_modules/.pnpm/@dnd-kit_accessibility@3.1.1_react@19.2.0/node_modules/@dnd-kit/accessibility/dist/accessibility.esm.cjs +68 -0
  2. package/dist/node_modules/.pnpm/@dnd-kit_accessibility@3.1.1_react@19.2.0/node_modules/@dnd-kit/accessibility/dist/accessibility.esm.mjs +60 -0
  3. package/dist/node_modules/.pnpm/@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@dnd-kit/core/dist/core.esm.cjs +3937 -0
  4. package/dist/node_modules/.pnpm/@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@dnd-kit/core/dist/core.esm.mjs +3907 -0
  5. package/dist/node_modules/.pnpm/@dnd-kit_modifiers@9.0.0_@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0__react@19.2.0/node_modules/@dnd-kit/modifiers/dist/modifiers.esm.cjs +30 -0
  6. package/dist/node_modules/.pnpm/@dnd-kit_modifiers@9.0.0_@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0__react@19.2.0/node_modules/@dnd-kit/modifiers/dist/modifiers.esm.mjs +28 -0
  7. package/dist/node_modules/.pnpm/@dnd-kit_sortable@10.0.0_@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0__react@19.2.0/node_modules/@dnd-kit/sortable/dist/sortable.esm.cjs +675 -0
  8. package/dist/node_modules/.pnpm/@dnd-kit_sortable@10.0.0_@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0__react@19.2.0/node_modules/@dnd-kit/sortable/dist/sortable.esm.mjs +661 -0
  9. package/dist/node_modules/.pnpm/@dnd-kit_utilities@3.2.2_react@19.2.0/node_modules/@dnd-kit/utilities/dist/utilities.esm.cjs +358 -0
  10. package/dist/node_modules/.pnpm/@dnd-kit_utilities@3.2.2_react@19.2.0/node_modules/@dnd-kit/utilities/dist/utilities.esm.mjs +332 -0
  11. package/dist/node_modules/.pnpm/@radix-ui_react-tabs@1.1.13_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react@1_865f042350eb43f3338b0fffb33f6246/node_modules/@radix-ui/react-tabs/dist/index.cjs +211 -0
  12. package/dist/node_modules/.pnpm/@radix-ui_react-tabs@1.1.13_@types_react-dom@19.2.3_@types_react@19.2.6__@types_react@1_865f042350eb43f3338b0fffb33f6246/node_modules/@radix-ui/react-tabs/dist/index.mjs +188 -0
  13. package/dist/packages/better-stack/src/plugins/cms/api/plugin.cjs +3 -2
  14. package/dist/packages/better-stack/src/plugins/cms/api/plugin.mjs +3 -2
  15. package/dist/packages/better-stack/src/plugins/cms/client/components/forms/content-form.cjs +15 -15
  16. package/dist/packages/better-stack/src/plugins/cms/client/components/forms/content-form.mjs +16 -16
  17. package/dist/packages/better-stack/src/plugins/form-builder/api/plugin.cjs +588 -0
  18. package/dist/packages/better-stack/src/plugins/form-builder/api/plugin.mjs +586 -0
  19. package/dist/packages/better-stack/src/plugins/form-builder/client/components/forms/form-renderer.cjs +131 -0
  20. package/dist/packages/better-stack/src/plugins/form-builder/client/components/forms/form-renderer.mjs +129 -0
  21. package/dist/packages/better-stack/src/plugins/form-builder/client/components/loading/form-builder-skeleton.cjs +32 -0
  22. package/dist/packages/better-stack/src/plugins/form-builder/client/components/loading/form-builder-skeleton.mjs +30 -0
  23. package/dist/packages/better-stack/src/plugins/form-builder/client/components/loading/form-list-skeleton.cjs +21 -0
  24. package/dist/packages/better-stack/src/plugins/form-builder/client/components/loading/form-list-skeleton.mjs +19 -0
  25. package/dist/packages/better-stack/src/plugins/form-builder/client/components/loading/submissions-skeleton.cjs +34 -0
  26. package/dist/packages/better-stack/src/plugins/form-builder/client/components/loading/submissions-skeleton.mjs +32 -0
  27. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/404-page.cjs +20 -0
  28. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/404-page.mjs +18 -0
  29. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/form-builder-page.cjs +19 -0
  30. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/form-builder-page.internal.cjs +186 -0
  31. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/form-builder-page.internal.mjs +184 -0
  32. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/form-builder-page.mjs +17 -0
  33. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/form-list-page.cjs +19 -0
  34. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/form-list-page.internal.cjs +165 -0
  35. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/form-list-page.internal.mjs +163 -0
  36. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/form-list-page.mjs +17 -0
  37. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/submissions-page.cjs +19 -0
  38. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.cjs +177 -0
  39. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.mjs +175 -0
  40. package/dist/packages/better-stack/src/plugins/form-builder/client/components/pages/submissions-page.mjs +17 -0
  41. package/dist/packages/better-stack/src/plugins/form-builder/client/components/shared/default-error.cjs +17 -0
  42. package/dist/packages/better-stack/src/plugins/form-builder/client/components/shared/default-error.mjs +15 -0
  43. package/dist/packages/better-stack/src/plugins/form-builder/client/components/shared/empty-state.cjs +16 -0
  44. package/dist/packages/better-stack/src/plugins/form-builder/client/components/shared/empty-state.mjs +14 -0
  45. package/dist/packages/better-stack/src/plugins/form-builder/client/components/shared/page-wrapper.cjs +27 -0
  46. package/dist/packages/better-stack/src/plugins/form-builder/client/components/shared/page-wrapper.mjs +25 -0
  47. package/dist/packages/better-stack/src/plugins/form-builder/client/components/shared/pagination.cjs +39 -0
  48. package/dist/packages/better-stack/src/plugins/form-builder/client/components/shared/pagination.mjs +37 -0
  49. package/dist/packages/better-stack/src/plugins/form-builder/client/hooks/form-builder-hooks.cjs +551 -0
  50. package/dist/packages/better-stack/src/plugins/form-builder/client/hooks/form-builder-hooks.mjs +537 -0
  51. package/dist/packages/better-stack/src/plugins/form-builder/client/localization/form-builder-common.cjs +36 -0
  52. package/dist/packages/better-stack/src/plugins/form-builder/client/localization/form-builder-common.mjs +34 -0
  53. package/dist/packages/better-stack/src/plugins/form-builder/client/localization/form-builder-editor.cjs +19 -0
  54. package/dist/packages/better-stack/src/plugins/form-builder/client/localization/form-builder-editor.mjs +17 -0
  55. package/dist/packages/better-stack/src/plugins/form-builder/client/localization/form-builder-list.cjs +21 -0
  56. package/dist/packages/better-stack/src/plugins/form-builder/client/localization/form-builder-list.mjs +19 -0
  57. package/dist/packages/better-stack/src/plugins/form-builder/client/localization/form-builder-submissions.cjs +19 -0
  58. package/dist/packages/better-stack/src/plugins/form-builder/client/localization/form-builder-submissions.mjs +17 -0
  59. package/dist/packages/better-stack/src/plugins/form-builder/client/localization/form-builder-toasts.cjs +14 -0
  60. package/dist/packages/better-stack/src/plugins/form-builder/client/localization/form-builder-toasts.mjs +12 -0
  61. package/dist/packages/better-stack/src/plugins/form-builder/client/localization/index.cjs +17 -0
  62. package/dist/packages/better-stack/src/plugins/form-builder/client/localization/index.mjs +15 -0
  63. package/dist/packages/better-stack/src/plugins/form-builder/client/plugin.cjs +278 -0
  64. package/dist/packages/better-stack/src/plugins/form-builder/client/plugin.mjs +276 -0
  65. package/dist/packages/better-stack/src/plugins/form-builder/db.cjs +99 -0
  66. package/dist/packages/better-stack/src/plugins/form-builder/db.mjs +97 -0
  67. package/dist/packages/better-stack/src/plugins/form-builder/schemas.cjs +82 -0
  68. package/dist/packages/better-stack/src/plugins/form-builder/schemas.mjs +74 -0
  69. package/dist/packages/better-stack/src/plugins/form-builder/utils.cjs +37 -0
  70. package/dist/packages/better-stack/src/plugins/form-builder/utils.mjs +29 -0
  71. package/dist/packages/ui/src/components/auto-form/index.cjs +2 -12
  72. package/dist/packages/ui/src/components/auto-form/index.mjs +2 -9
  73. package/dist/packages/ui/src/components/auto-form/stepped-auto-form.cjs +377 -0
  74. package/dist/packages/ui/src/components/auto-form/stepped-auto-form.mjs +368 -0
  75. package/dist/packages/ui/src/components/auto-form/utils.cjs +1 -56
  76. package/dist/packages/ui/src/components/auto-form/utils.mjs +2 -56
  77. package/dist/packages/ui/src/components/form-builder/canvas.cjs +111 -0
  78. package/dist/packages/ui/src/components/form-builder/canvas.mjs +109 -0
  79. package/dist/packages/ui/src/components/form-builder/components/index.cjs +570 -0
  80. package/dist/packages/ui/src/components/form-builder/components/index.mjs +553 -0
  81. package/dist/packages/ui/src/components/form-builder/edit-field-dialog.cjs +131 -0
  82. package/dist/packages/ui/src/components/form-builder/edit-field-dialog.mjs +129 -0
  83. package/dist/packages/ui/src/components/form-builder/form-preview.cjs +73 -0
  84. package/dist/packages/ui/src/components/form-builder/form-preview.mjs +71 -0
  85. package/dist/packages/ui/src/components/form-builder/index.cjs +353 -0
  86. package/dist/packages/ui/src/components/form-builder/index.mjs +344 -0
  87. package/dist/packages/ui/src/components/form-builder/nested-field-editor-dialog.cjs +263 -0
  88. package/dist/packages/ui/src/components/form-builder/nested-field-editor-dialog.mjs +261 -0
  89. package/dist/packages/ui/src/components/form-builder/palette.cjs +52 -0
  90. package/dist/packages/ui/src/components/form-builder/palette.mjs +49 -0
  91. package/dist/packages/ui/src/components/form-builder/schema-utils.cjs +120 -0
  92. package/dist/packages/ui/src/components/form-builder/schema-utils.mjs +114 -0
  93. package/dist/packages/ui/src/components/form-builder/sortable-field.cjs +151 -0
  94. package/dist/packages/ui/src/components/form-builder/sortable-field.mjs +148 -0
  95. package/dist/packages/ui/src/components/form-builder/step-tabs.cjs +180 -0
  96. package/dist/packages/ui/src/components/form-builder/step-tabs.mjs +178 -0
  97. package/dist/packages/ui/src/components/form-builder/types.cjs +7 -0
  98. package/dist/packages/ui/src/components/form-builder/types.mjs +5 -0
  99. package/dist/packages/ui/src/components/form-builder/validation-schemas.cjs +67 -0
  100. package/dist/packages/ui/src/components/form-builder/validation-schemas.mjs +56 -0
  101. package/dist/packages/ui/src/components/tabs.cjs +70 -0
  102. package/dist/packages/ui/src/components/tabs.mjs +65 -0
  103. package/dist/packages/ui/src/lib/schema-converter.cjs +130 -0
  104. package/dist/packages/ui/src/lib/schema-converter.mjs +124 -0
  105. package/dist/plugins/blog/api/index.d.cts +1 -1
  106. package/dist/plugins/blog/api/index.d.mts +1 -1
  107. package/dist/plugins/blog/api/index.d.ts +1 -1
  108. package/dist/plugins/blog/client/hooks/index.d.cts +2 -2
  109. package/dist/plugins/blog/client/hooks/index.d.mts +2 -2
  110. package/dist/plugins/blog/client/hooks/index.d.ts +2 -2
  111. package/dist/plugins/blog/client/index.d.cts +1 -1
  112. package/dist/plugins/blog/client/index.d.mts +1 -1
  113. package/dist/plugins/blog/client/index.d.ts +1 -1
  114. package/dist/plugins/blog/query-keys.d.cts +2 -2
  115. package/dist/plugins/blog/query-keys.d.mts +2 -2
  116. package/dist/plugins/blog/query-keys.d.ts +2 -2
  117. package/dist/plugins/cms/client/index.cjs +6 -0
  118. package/dist/plugins/cms/client/index.d.cts +6 -113
  119. package/dist/plugins/cms/client/index.d.mts +6 -113
  120. package/dist/plugins/cms/client/index.d.ts +6 -113
  121. package/dist/plugins/cms/client/index.mjs +1 -0
  122. package/dist/plugins/form-builder/api/index.cjs +7 -0
  123. package/dist/plugins/form-builder/api/index.d.cts +141 -0
  124. package/dist/plugins/form-builder/api/index.d.mts +141 -0
  125. package/dist/plugins/form-builder/api/index.d.ts +141 -0
  126. package/dist/plugins/form-builder/api/index.mjs +1 -0
  127. package/dist/plugins/form-builder/client/components/index.cjs +29 -0
  128. package/dist/plugins/form-builder/client/components/index.d.cts +93 -0
  129. package/dist/plugins/form-builder/client/components/index.d.mts +93 -0
  130. package/dist/plugins/form-builder/client/components/index.d.ts +93 -0
  131. package/dist/plugins/form-builder/client/components/index.mjs +18 -0
  132. package/dist/plugins/form-builder/client/hooks/index.cjs +19 -0
  133. package/dist/plugins/form-builder/client/hooks/index.d.cts +154 -0
  134. package/dist/plugins/form-builder/client/hooks/index.d.mts +154 -0
  135. package/dist/plugins/form-builder/client/hooks/index.d.ts +154 -0
  136. package/dist/plugins/form-builder/client/hooks/index.mjs +1 -0
  137. package/dist/plugins/form-builder/client/index.cjs +13 -0
  138. package/dist/plugins/form-builder/client/index.d.cts +381 -0
  139. package/dist/plugins/form-builder/client/index.d.mts +381 -0
  140. package/dist/plugins/form-builder/client/index.d.ts +381 -0
  141. package/dist/plugins/form-builder/client/index.mjs +2 -0
  142. package/dist/plugins/form-builder/client.css +3 -0
  143. package/dist/plugins/form-builder/query-keys.cjs +143 -0
  144. package/dist/plugins/form-builder/query-keys.d.cts +74 -0
  145. package/dist/plugins/form-builder/query-keys.d.mts +74 -0
  146. package/dist/plugins/form-builder/query-keys.d.ts +74 -0
  147. package/dist/plugins/form-builder/query-keys.mjs +141 -0
  148. package/dist/plugins/form-builder/style.css +19 -0
  149. package/dist/shared/stack.AX5nZ6A3.d.cts +86 -0
  150. package/dist/shared/stack.AX5nZ6A3.d.mts +86 -0
  151. package/dist/shared/stack.AX5nZ6A3.d.ts +86 -0
  152. package/dist/shared/stack.BIh2AXaW.d.cts +123 -0
  153. package/dist/shared/stack.BIh2AXaW.d.mts +123 -0
  154. package/dist/shared/stack.BIh2AXaW.d.ts +123 -0
  155. package/dist/shared/stack.DzH_wcvr.d.cts +195 -0
  156. package/dist/shared/stack.DzH_wcvr.d.mts +195 -0
  157. package/dist/shared/stack.DzH_wcvr.d.ts +195 -0
  158. package/package.json +54 -1
  159. package/src/plugins/cms/api/plugin.ts +9 -4
  160. package/src/plugins/cms/client/components/forms/content-form.tsx +23 -25
  161. package/src/plugins/cms/client/index.ts +11 -0
  162. package/src/plugins/form-builder/api/index.ts +1 -0
  163. package/src/plugins/form-builder/api/plugin.ts +776 -0
  164. package/src/plugins/form-builder/client/components/forms/form-renderer.tsx +253 -0
  165. package/src/plugins/form-builder/client/components/index.tsx +24 -0
  166. package/src/plugins/form-builder/client/components/loading/form-builder-skeleton.tsx +42 -0
  167. package/src/plugins/form-builder/client/components/loading/form-list-skeleton.tsx +25 -0
  168. package/src/plugins/form-builder/client/components/loading/index.tsx +3 -0
  169. package/src/plugins/form-builder/client/components/loading/submissions-skeleton.tsx +40 -0
  170. package/src/plugins/form-builder/client/components/pages/404-page.tsx +28 -0
  171. package/src/plugins/form-builder/client/components/pages/form-builder-page.internal.tsx +253 -0
  172. package/src/plugins/form-builder/client/components/pages/form-builder-page.tsx +26 -0
  173. package/src/plugins/form-builder/client/components/pages/form-list-page.internal.tsx +231 -0
  174. package/src/plugins/form-builder/client/components/pages/form-list-page.tsx +22 -0
  175. package/src/plugins/form-builder/client/components/pages/submissions-page.internal.tsx +268 -0
  176. package/src/plugins/form-builder/client/components/pages/submissions-page.tsx +26 -0
  177. package/src/plugins/form-builder/client/components/shared/default-error.tsx +30 -0
  178. package/src/plugins/form-builder/client/components/shared/empty-state.tsx +26 -0
  179. package/src/plugins/form-builder/client/components/shared/page-wrapper.tsx +32 -0
  180. package/src/plugins/form-builder/client/components/shared/pagination.tsx +52 -0
  181. package/src/plugins/form-builder/client/hooks/form-builder-hooks.tsx +799 -0
  182. package/src/plugins/form-builder/client/hooks/index.tsx +1 -0
  183. package/src/plugins/form-builder/client/index.ts +22 -0
  184. package/src/plugins/form-builder/client/localization/form-builder-common.ts +36 -0
  185. package/src/plugins/form-builder/client/localization/form-builder-editor.ts +18 -0
  186. package/src/plugins/form-builder/client/localization/form-builder-list.ts +17 -0
  187. package/src/plugins/form-builder/client/localization/form-builder-submissions.ts +17 -0
  188. package/src/plugins/form-builder/client/localization/form-builder-toasts.ts +10 -0
  189. package/src/plugins/form-builder/client/localization/index.ts +15 -0
  190. package/src/plugins/form-builder/client/overrides.ts +146 -0
  191. package/src/plugins/form-builder/client/plugin.tsx +488 -0
  192. package/src/plugins/form-builder/client.css +3 -0
  193. package/src/plugins/form-builder/db.ts +99 -0
  194. package/src/plugins/form-builder/query-keys.ts +198 -0
  195. package/src/plugins/form-builder/schemas.ts +122 -0
  196. package/src/plugins/form-builder/style.css +19 -0
  197. package/src/plugins/form-builder/types.ts +317 -0
  198. package/src/plugins/form-builder/utils.ts +63 -0
  199. package/dist/shared/{stack.DLhzx1-D.d.cts → stack.CcI4sYJP.d.cts} +1 -1
  200. package/dist/shared/{stack.DLhzx1-D.d.mts → stack.CcI4sYJP.d.mts} +1 -1
  201. package/dist/shared/{stack.DLhzx1-D.d.ts → stack.CcI4sYJP.d.ts} +1 -1
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Form Builder Plugin Types
3
+ *
4
+ * Key distinction from CMS Plugin:
5
+ * - CMS uses developer-defined Zod schemas in code
6
+ * - Form Builder allows non-technical admins to build forms via drag-and-drop UI
7
+ * - Forms are serialized to/from JSON Schema for storage
8
+ */
9
+ /**
10
+ * Form stored in the database
11
+ */
12
+ type Form = {
13
+ id: string;
14
+ /** Display name for the form */
15
+ name: string;
16
+ /** URL-friendly slug - unique identifier for public access */
17
+ slug: string;
18
+ /** Optional description for admin UI */
19
+ description?: string;
20
+ /** JSON Schema stored as string (includes steps, fieldType, stepGroup, etc.) */
21
+ schema: string;
22
+ /** Optional custom success message after submission */
23
+ successMessage?: string;
24
+ /** Optional redirect URL after submission */
25
+ redirectUrl?: string;
26
+ /** Form status: active, inactive, archived */
27
+ status: "active" | "inactive" | "archived";
28
+ /** User who created the form */
29
+ createdBy?: string;
30
+ createdAt: Date;
31
+ updatedAt: Date;
32
+ };
33
+ /**
34
+ * Form submission stored in the database
35
+ */
36
+ type FormSubmission = {
37
+ id: string;
38
+ /** Reference to the form */
39
+ formId: string;
40
+ /** Submitted data as JSON string */
41
+ data: string;
42
+ /** Submission timestamp */
43
+ submittedAt: Date;
44
+ /** Optional user ID if authenticated */
45
+ submittedBy?: string;
46
+ /** Client IP address for rate limiting and spam protection */
47
+ ipAddress?: string;
48
+ /** User agent for analytics */
49
+ userAgent?: string;
50
+ };
51
+ /**
52
+ * Serialized form for API responses (dates as strings)
53
+ */
54
+ interface SerializedForm extends Omit<Form, "createdAt" | "updatedAt" | "status"> {
55
+ status: string;
56
+ createdAt: string;
57
+ updatedAt: string;
58
+ }
59
+ /**
60
+ * Serialized form submission for API responses (dates as strings)
61
+ */
62
+ interface SerializedFormSubmission extends Omit<FormSubmission, "submittedAt"> {
63
+ submittedAt: string;
64
+ }
65
+ /**
66
+ * Serialized form submission with parsed data
67
+ */
68
+ interface SerializedFormSubmissionWithData<TData = Record<string, unknown>> extends SerializedFormSubmission {
69
+ /** Parsed data object (JSON.parse of data field) */
70
+ parsedData: TData;
71
+ /** Joined form */
72
+ form?: SerializedForm;
73
+ }
74
+ /**
75
+ * Paginated list response for forms
76
+ */
77
+ interface PaginatedForms {
78
+ items: SerializedForm[];
79
+ total: number;
80
+ limit: number;
81
+ offset: number;
82
+ }
83
+ /**
84
+ * Paginated list response for form submissions
85
+ */
86
+ interface PaginatedFormSubmissions<TData = Record<string, unknown>> {
87
+ items: SerializedFormSubmissionWithData<TData>[];
88
+ total: number;
89
+ limit: number;
90
+ offset: number;
91
+ }
92
+ /**
93
+ * Context passed to all backend hooks
94
+ */
95
+ interface FormBuilderHookContext {
96
+ /** User ID if authenticated */
97
+ userId?: string;
98
+ /** Request headers */
99
+ headers?: Headers;
100
+ /** Client IP address (for rate limiting) */
101
+ ipAddress?: string;
102
+ /** User agent string */
103
+ userAgent?: string;
104
+ }
105
+ /**
106
+ * Context for submission-specific hooks
107
+ */
108
+ interface SubmissionHookContext extends FormBuilderHookContext {
109
+ /** Form slug being submitted */
110
+ formSlug: string;
111
+ /** Form ID */
112
+ formId: string;
113
+ }
114
+ /**
115
+ * Input data for creating a form
116
+ */
117
+ interface FormInput {
118
+ name: string;
119
+ slug: string;
120
+ description?: string;
121
+ schema: string;
122
+ successMessage?: string;
123
+ redirectUrl?: string;
124
+ status?: "active" | "inactive" | "archived";
125
+ createdBy?: string;
126
+ }
127
+ /**
128
+ * Input data for updating a form
129
+ */
130
+ interface FormUpdate {
131
+ name?: string;
132
+ slug?: string;
133
+ description?: string;
134
+ schema?: string;
135
+ successMessage?: string;
136
+ redirectUrl?: string;
137
+ status?: "active" | "inactive" | "archived";
138
+ }
139
+ /**
140
+ * Backend hooks for Form Builder plugin
141
+ *
142
+ * All CRUD hooks receive ipAddress and headers for auth/rate limiting.
143
+ * Return false from onBefore* hooks to reject the operation (throws 403).
144
+ */
145
+ interface FormBuilderBackendHooks {
146
+ /** Called before listing forms. Return false to deny access (403). */
147
+ onBeforeListForms?: (ctx: FormBuilderHookContext) => Promise<boolean> | boolean;
148
+ /** Called before creating a form. Return false to deny, or modified data. */
149
+ onBeforeFormCreated?: (data: FormInput, ctx: FormBuilderHookContext) => Promise<FormInput | false> | FormInput | false;
150
+ /** Called after a form is created */
151
+ onAfterFormCreated?: (form: SerializedForm, ctx: FormBuilderHookContext) => Promise<void> | void;
152
+ /** Called before getting a form by ID or slug. Return false to deny access. */
153
+ onBeforeGetForm?: (idOrSlug: string, ctx: FormBuilderHookContext) => Promise<boolean> | boolean;
154
+ /** Called before updating a form. Return false to deny, or modified data. */
155
+ onBeforeFormUpdated?: (id: string, data: FormUpdate, ctx: FormBuilderHookContext) => Promise<FormUpdate | false> | FormUpdate | false;
156
+ /** Called after a form is updated */
157
+ onAfterFormUpdated?: (form: SerializedForm, ctx: FormBuilderHookContext) => Promise<void> | void;
158
+ /** Called before deleting a form. Return false to deny. */
159
+ onBeforeFormDeleted?: (id: string, ctx: FormBuilderHookContext) => Promise<boolean> | boolean;
160
+ /** Called after a form is deleted */
161
+ onAfterFormDeleted?: (id: string, ctx: FormBuilderHookContext) => Promise<void> | void;
162
+ /**
163
+ * Called before processing a form submission.
164
+ * Use for: spam protection, rate limiting, data validation/enrichment.
165
+ *
166
+ * @returns false to reject submission (400), or modified data to continue
167
+ */
168
+ onBeforeSubmission?: (formSlug: string, data: Record<string, unknown>, ctx: SubmissionHookContext) => Promise<Record<string, unknown> | false> | Record<string, unknown> | false;
169
+ /**
170
+ * Called after a submission is saved.
171
+ * Use for: sending emails, storing in CRM, triggering workflows.
172
+ */
173
+ onAfterSubmission?: (submission: SerializedFormSubmission, form: SerializedForm, ctx: SubmissionHookContext) => Promise<void> | void;
174
+ /** Called when a submission fails */
175
+ onSubmissionError?: (error: Error, formSlug: string, data: Record<string, unknown>, ctx: SubmissionHookContext) => Promise<void> | void;
176
+ /** Called before listing submissions. Return false to deny access (403). */
177
+ onBeforeListSubmissions?: (formId: string, ctx: FormBuilderHookContext) => Promise<boolean> | boolean;
178
+ /** Called before getting a submission. Return false to deny access. */
179
+ onBeforeGetSubmission?: (submissionId: string, ctx: FormBuilderHookContext) => Promise<boolean> | boolean;
180
+ /** Called before deleting a submission. Return false to deny. */
181
+ onBeforeSubmissionDeleted?: (submissionId: string, ctx: FormBuilderHookContext) => Promise<boolean> | boolean;
182
+ /** Called after a submission is deleted */
183
+ onAfterSubmissionDeleted?: (submissionId: string, ctx: FormBuilderHookContext) => Promise<void> | void;
184
+ /** Called on any error */
185
+ onError?: (error: Error, operation: "list" | "get" | "create" | "update" | "delete" | "submit" | "listSubmissions" | "getSubmission" | "deleteSubmission", ctx: FormBuilderHookContext) => Promise<void> | void;
186
+ }
187
+ /**
188
+ * Configuration for the Form Builder backend plugin
189
+ */
190
+ interface FormBuilderBackendConfig {
191
+ /** Optional hooks for customizing behavior */
192
+ hooks?: FormBuilderBackendHooks;
193
+ }
194
+
195
+ export type { FormBuilderBackendConfig as F, PaginatedForms as P, SerializedForm as S, SerializedFormSubmission as a, SerializedFormSubmissionWithData as b, PaginatedFormSubmissions as c };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@btst/stack",
3
- "version": "1.5.2",
3
+ "version": "1.6.0",
4
4
  "description": "A composable, plugin-based library for building full-stack applications.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -206,6 +206,47 @@
206
206
  }
207
207
  },
208
208
  "./plugins/cms/css": "./dist/plugins/cms/style.css",
209
+ "./plugins/form-builder/api": {
210
+ "import": {
211
+ "types": "./dist/plugins/form-builder/api/index.d.ts",
212
+ "default": "./dist/plugins/form-builder/api/index.mjs"
213
+ },
214
+ "require": {
215
+ "types": "./dist/plugins/form-builder/api/index.d.cts",
216
+ "default": "./dist/plugins/form-builder/api/index.cjs"
217
+ }
218
+ },
219
+ "./plugins/form-builder/client": {
220
+ "import": {
221
+ "types": "./dist/plugins/form-builder/client/index.d.ts",
222
+ "default": "./dist/plugins/form-builder/client/index.mjs"
223
+ },
224
+ "require": {
225
+ "types": "./dist/plugins/form-builder/client/index.d.cts",
226
+ "default": "./dist/plugins/form-builder/client/index.cjs"
227
+ }
228
+ },
229
+ "./plugins/form-builder/client/components": {
230
+ "import": {
231
+ "types": "./dist/plugins/form-builder/client/components/index.d.ts",
232
+ "default": "./dist/plugins/form-builder/client/components/index.mjs"
233
+ },
234
+ "require": {
235
+ "types": "./dist/plugins/form-builder/client/components/index.d.cts",
236
+ "default": "./dist/plugins/form-builder/client/components/index.cjs"
237
+ }
238
+ },
239
+ "./plugins/form-builder/client/hooks": {
240
+ "import": {
241
+ "types": "./dist/plugins/form-builder/client/hooks/index.d.ts",
242
+ "default": "./dist/plugins/form-builder/client/hooks/index.mjs"
243
+ },
244
+ "require": {
245
+ "types": "./dist/plugins/form-builder/client/hooks/index.d.cts",
246
+ "default": "./dist/plugins/form-builder/client/hooks/index.cjs"
247
+ }
248
+ },
249
+ "./plugins/form-builder/css": "./dist/plugins/form-builder/style.css",
209
250
  "./dist/*": "./dist/*",
210
251
  "./ui/css": "./dist/ui/components.css",
211
252
  "./package.json": "./package.json"
@@ -259,6 +300,18 @@
259
300
  ],
260
301
  "plugins/cms/client/hooks": [
261
302
  "./dist/plugins/cms/client/hooks/index.d.ts"
303
+ ],
304
+ "plugins/form-builder/api": [
305
+ "./dist/plugins/form-builder/api/index.d.ts"
306
+ ],
307
+ "plugins/form-builder/client": [
308
+ "./dist/plugins/form-builder/client/index.d.ts"
309
+ ],
310
+ "plugins/form-builder/client/components": [
311
+ "./dist/plugins/form-builder/client/components/index.d.ts"
312
+ ],
313
+ "plugins/form-builder/client/hooks": [
314
+ "./dist/plugins/form-builder/client/hooks/index.d.ts"
262
315
  ]
263
316
  }
264
317
  },
@@ -2,6 +2,10 @@ import type { Adapter } from "@btst/db";
2
2
  import { defineBackendPlugin } from "@btst/stack/plugins/api";
3
3
  import { createEndpoint } from "@btst/stack/plugins/api";
4
4
  import { z } from "zod";
5
+ import {
6
+ zodToFormSchema,
7
+ formSchemaToZod,
8
+ } from "@workspace/ui/lib/schema-converter";
5
9
  import { cmsSchema as dbSchema } from "../db";
6
10
  import type {
7
11
  ContentType,
@@ -124,8 +128,9 @@ async function syncContentTypes(
124
128
  config: CMSBackendConfig,
125
129
  ): Promise<void> {
126
130
  for (const ct of config.contentTypes) {
127
- // Convert Zod schema to JSON Schema - fieldType is now embedded via .meta()
128
- const jsonSchema = JSON.stringify(z.toJSONSchema(ct.schema));
131
+ // Convert Zod schema to JSON Schema using zodToFormSchema
132
+ // This properly handles dates, date constraints, and steps metadata
133
+ const jsonSchema = JSON.stringify(zodToFormSchema(ct.schema));
129
134
 
130
135
  const existing = await adapter.findOne<ContentType>({
131
136
  model: "contentType",
@@ -184,11 +189,11 @@ async function syncContentTypes(
184
189
 
185
190
  /**
186
191
  * Get Zod schema for a content type from its JSON Schema
187
- * Uses Zod v4's native z.fromJSONSchema() for conversion
192
+ * Uses formSchemaToZod to properly handle dates, date constraints, and steps metadata
188
193
  */
189
194
  function getContentTypeZodSchema(contentType: ContentType): z.ZodTypeAny {
190
195
  const jsonSchema = JSON.parse(contentType.jsonSchema);
191
- return z.fromJSONSchema(jsonSchema);
196
+ return formSchemaToZod(jsonSchema);
192
197
  }
193
198
 
194
199
  /**
@@ -3,15 +3,13 @@
3
3
  import { useState, useMemo, useEffect } from "react";
4
4
  import { z } from "zod";
5
5
  import { toast } from "sonner";
6
- import AutoForm, { AutoFormSubmit } from "@workspace/ui/components/auto-form";
6
+ import { SteppedAutoForm } from "@workspace/ui/components/auto-form/stepped-auto-form";
7
7
  import type {
8
8
  FieldConfig,
9
9
  AutoFormInputComponentProps,
10
10
  } from "@workspace/ui/components/auto-form/types";
11
- import {
12
- buildFieldConfigFromJsonSchema as buildFieldConfigBase,
13
- fromJSONSchemaWithDates,
14
- } from "@workspace/ui/components/auto-form/utils";
11
+ import { buildFieldConfigFromJsonSchema as buildFieldConfigBase } from "@workspace/ui/components/auto-form/utils";
12
+ import { formSchemaToZod } from "@workspace/ui/lib/schema-converter";
15
13
  import { Input } from "@workspace/ui/components/input";
16
14
  import { Label } from "@workspace/ui/components/label";
17
15
  import { Badge } from "@workspace/ui/components/badge";
@@ -168,11 +166,11 @@ export function ContentForm({
168
166
  }
169
167
  }, [contentType.jsonSchema]);
170
168
 
171
- // Convert JSON Schema to Zod schema using fromJSONSchemaWithDates utility
169
+ // Convert JSON Schema to Zod schema using formSchemaToZod utility
172
170
  // This properly handles date fields (format: "date-time") and min/max date constraints
173
171
  const zodSchema = useMemo(() => {
174
172
  try {
175
- return fromJSONSchemaWithDates(jsonSchema);
173
+ return formSchemaToZod(jsonSchema);
176
174
  } catch {
177
175
  return z.object({});
178
176
  }
@@ -264,30 +262,30 @@ export function ContentForm({
264
262
  </div>
265
263
 
266
264
  {/* Dynamic form from Zod schema */}
267
- <AutoForm
265
+ {/* Uses SteppedAutoForm which automatically handles both single-step and multi-step content types */}
266
+ <SteppedAutoForm
268
267
  formSchema={zodSchema as z.ZodObject<any, any>}
269
268
  values={formData as any}
270
269
  onValuesChange={handleValuesChange as any}
271
270
  onSubmit={handleSubmit as any}
272
271
  fieldConfig={fieldConfig as any}
272
+ isSubmitting={isSubmitting}
273
+ submitButtonText={
274
+ isSubmitting
275
+ ? localization.CMS_STATUS_SAVING
276
+ : localization.CMS_BUTTON_SAVE
277
+ }
273
278
  >
274
- <div className="flex items-center gap-2 pt-4">
275
- <AutoFormSubmit disabled={isSubmitting}>
276
- {isSubmitting
277
- ? localization.CMS_STATUS_SAVING
278
- : localization.CMS_BUTTON_SAVE}
279
- </AutoFormSubmit>
280
- {onCancel && (
281
- <button
282
- type="button"
283
- onClick={onCancel}
284
- className="px-4 py-2 text-sm text-muted-foreground hover:text-foreground"
285
- >
286
- {localization.CMS_BUTTON_CANCEL}
287
- </button>
288
- )}
289
- </div>
290
- </AutoForm>
279
+ {onCancel && (
280
+ <button
281
+ type="button"
282
+ onClick={onCancel}
283
+ className="px-4 py-2 text-sm text-muted-foreground hover:text-foreground"
284
+ >
285
+ {localization.CMS_BUTTON_CANCEL}
286
+ </button>
287
+ )}
288
+ </SteppedAutoForm>
291
289
  </div>
292
290
  );
293
291
  }
@@ -6,6 +6,17 @@ export type { CMSLocalization } from "./localization";
6
6
  // Re-export AutoFormInputComponentProps for custom field components
7
7
  export type { AutoFormInputComponentProps } from "@workspace/ui/components/auto-form/types";
8
8
 
9
+ // Re-export schema converter utilities
10
+ export {
11
+ zodToFormSchema,
12
+ formSchemaToZod,
13
+ hasSteps,
14
+ getSteps,
15
+ getStepGroupMap,
16
+ type FormStep,
17
+ type FormSchemaMetadata,
18
+ } from "@workspace/ui/lib/schema-converter";
19
+
9
20
  // Export CMSFileUpload for consumers to use or extend
10
21
  export {
11
22
  CMSFileUpload,
@@ -0,0 +1 @@
1
+ export { formBuilderBackendPlugin, type FormBuilderApiRouter } from "./plugin";