@btst/plugin-cms 0.0.0-stage → 1.0.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.
- package/LICENSE.md +17 -0
- package/dist/api/getters.cjs +328 -0
- package/dist/api/getters.mjs +314 -0
- package/dist/api/index.cjs +29 -0
- package/dist/api/index.d.cts +209 -0
- package/dist/api/index.d.mts +209 -0
- package/dist/api/index.d.ts +209 -0
- package/dist/api/index.mjs +7 -0
- package/dist/api/lifecycle-migrations.cjs +13 -0
- package/dist/api/lifecycle-migrations.mjs +11 -0
- package/dist/api/mutations.cjs +59 -0
- package/dist/api/mutations.mjs +57 -0
- package/dist/api/operations.cjs +1769 -0
- package/dist/api/operations.mjs +1762 -0
- package/dist/api/plugin.cjs +337 -0
- package/dist/api/plugin.mjs +331 -0
- package/dist/api/query-key-defs.cjs +44 -0
- package/dist/api/query-key-defs.mjs +39 -0
- package/dist/api/relations.cjs +76 -0
- package/dist/api/relations.mjs +70 -0
- package/dist/client/components/forms/content-form.cjs +286 -0
- package/dist/client/components/forms/content-form.mjs +284 -0
- package/dist/client/components/forms/file-upload.cjs +160 -0
- package/dist/client/components/forms/file-upload.mjs +158 -0
- package/dist/client/components/forms/relation-field.cjs +237 -0
- package/dist/client/components/forms/relation-field.mjs +235 -0
- package/dist/client/components/index.cjs +14 -0
- package/dist/client/components/index.d.cts +20 -0
- package/dist/client/components/index.d.mts +20 -0
- package/dist/client/components/index.d.ts +20 -0
- package/dist/client/components/index.mjs +10 -0
- package/dist/client/components/inverse-relations-panel.cjs +272 -0
- package/dist/client/components/inverse-relations-panel.mjs +270 -0
- package/dist/client/components/loading/dashboard-skeleton.cjs +18 -0
- package/dist/client/components/loading/dashboard-skeleton.mjs +16 -0
- package/dist/client/components/loading/editor-skeleton.cjs +32 -0
- package/dist/client/components/loading/editor-skeleton.mjs +30 -0
- package/dist/client/components/loading/list-skeleton.cjs +32 -0
- package/dist/client/components/loading/list-skeleton.mjs +30 -0
- package/dist/client/components/pages/404-page.cjs +26 -0
- package/dist/client/components/pages/404-page.mjs +24 -0
- package/dist/client/components/pages/content-editor-page.cjs +84 -0
- package/dist/client/components/pages/content-editor-page.internal.cjs +170 -0
- package/dist/client/components/pages/content-editor-page.internal.mjs +168 -0
- package/dist/client/components/pages/content-editor-page.mjs +82 -0
- package/dist/client/components/pages/content-list-page.cjs +49 -0
- package/dist/client/components/pages/content-list-page.internal.cjs +334 -0
- package/dist/client/components/pages/content-list-page.internal.mjs +332 -0
- package/dist/client/components/pages/content-list-page.mjs +47 -0
- package/dist/client/components/pages/dashboard-page.cjs +42 -0
- package/dist/client/components/pages/dashboard-page.internal.cjs +102 -0
- package/dist/client/components/pages/dashboard-page.internal.mjs +100 -0
- package/dist/client/components/pages/dashboard-page.mjs +40 -0
- package/dist/client/components/shared/default-error.cjs +17 -0
- package/dist/client/components/shared/default-error.mjs +15 -0
- package/dist/client/components/shared/empty-state.cjs +16 -0
- package/dist/client/components/shared/empty-state.mjs +14 -0
- package/dist/client/components/shared/page-wrapper.cjs +29 -0
- package/dist/client/components/shared/page-wrapper.mjs +27 -0
- package/dist/client/constants.cjs +5 -0
- package/dist/client/constants.mjs +3 -0
- package/dist/client/hooks/cms-hooks.cjs +300 -0
- package/dist/client/hooks/cms-hooks.mjs +280 -0
- package/dist/client/hooks/cms-resource.cjs +13 -0
- package/dist/client/hooks/cms-resource.mjs +11 -0
- package/dist/client/hooks/index.cjs +25 -0
- package/dist/client/hooks/index.d.cts +693 -0
- package/dist/client/hooks/index.d.mts +693 -0
- package/dist/client/hooks/index.d.ts +693 -0
- package/dist/client/hooks/index.mjs +1 -0
- package/dist/client/index.cjs +15 -0
- package/dist/client/index.d.cts +654 -0
- package/dist/client/index.d.mts +654 -0
- package/dist/client/index.d.ts +654 -0
- package/dist/client/index.mjs +3 -0
- package/dist/client/overrides.cjs +26 -0
- package/dist/client/overrides.mjs +24 -0
- package/dist/client/plugin.cjs +316 -0
- package/dist/client/plugin.mjs +314 -0
- package/dist/client.css +3 -0
- package/dist/db.cjs +118 -0
- package/dist/db.mjs +116 -0
- package/dist/permissions.cjs +46 -0
- package/dist/permissions.d.cts +42 -0
- package/dist/permissions.d.mts +42 -0
- package/dist/permissions.d.ts +42 -0
- package/dist/permissions.mjs +44 -0
- package/dist/query-keys.cjs +229 -0
- package/dist/query-keys.d.cts +8 -0
- package/dist/query-keys.d.mts +8 -0
- package/dist/query-keys.d.ts +8 -0
- package/dist/query-keys.mjs +225 -0
- package/dist/schemas.cjs +81 -0
- package/dist/schemas.mjs +72 -0
- package/dist/shared/plugin-cms.BBshPRkb.d.cts +6 -0
- package/dist/shared/plugin-cms.BBshPRkb.d.mts +6 -0
- package/dist/shared/plugin-cms.BBshPRkb.d.ts +6 -0
- package/dist/shared/plugin-cms.DQLAoogy.d.ts +1749 -0
- package/dist/shared/plugin-cms.W4Le8D91.d.mts +1749 -0
- package/dist/shared/plugin-cms.c-GeWvTf.d.cts +1749 -0
- package/dist/style.css +6 -0
- package/dist/types.cjs +2 -0
- package/dist/types.d.cts +406 -0
- package/dist/types.d.mts +406 -0
- package/dist/types.d.ts +406 -0
- package/dist/types.mjs +1 -0
- package/dist/ui/src/components/accordion.cjs +81 -0
- package/dist/ui/src/components/accordion.mjs +62 -0
- package/dist/ui/src/components/alert-dialog.cjs +157 -0
- package/dist/ui/src/components/alert-dialog.mjs +132 -0
- package/dist/ui/src/components/auto-form/common/label.cjs +18 -0
- package/dist/ui/src/components/auto-form/common/label.mjs +16 -0
- package/dist/ui/src/components/auto-form/common/tooltip.cjs +9 -0
- package/dist/ui/src/components/auto-form/common/tooltip.mjs +7 -0
- package/dist/ui/src/components/auto-form/config.cjs +40 -0
- package/dist/ui/src/components/auto-form/config.mjs +37 -0
- package/dist/ui/src/components/auto-form/dependencies.cjs +48 -0
- package/dist/ui/src/components/auto-form/dependencies.mjs +46 -0
- package/dist/ui/src/components/auto-form/fields/array.cjs +266 -0
- package/dist/ui/src/components/auto-form/fields/array.mjs +264 -0
- package/dist/ui/src/components/auto-form/fields/checkbox.cjs +38 -0
- package/dist/ui/src/components/auto-form/fields/checkbox.mjs +36 -0
- package/dist/ui/src/components/auto-form/fields/date.cjs +67 -0
- package/dist/ui/src/components/auto-form/fields/date.mjs +65 -0
- package/dist/ui/src/components/auto-form/fields/enum.cjs +73 -0
- package/dist/ui/src/components/auto-form/fields/enum.mjs +71 -0
- package/dist/ui/src/components/auto-form/fields/input.cjs +32 -0
- package/dist/ui/src/components/auto-form/fields/input.mjs +30 -0
- package/dist/ui/src/components/auto-form/fields/number.cjs +31 -0
- package/dist/ui/src/components/auto-form/fields/number.mjs +29 -0
- package/dist/ui/src/components/auto-form/fields/object.cjs +233 -0
- package/dist/ui/src/components/auto-form/fields/object.mjs +217 -0
- package/dist/ui/src/components/auto-form/fields/radio-group.cjs +67 -0
- package/dist/ui/src/components/auto-form/fields/radio-group.mjs +65 -0
- package/dist/ui/src/components/auto-form/fields/switch.cjs +38 -0
- package/dist/ui/src/components/auto-form/fields/switch.mjs +36 -0
- package/dist/ui/src/components/auto-form/fields/textarea.cjs +31 -0
- package/dist/ui/src/components/auto-form/fields/textarea.mjs +29 -0
- package/dist/ui/src/components/auto-form/helpers.cjs +270 -0
- package/dist/ui/src/components/auto-form/helpers.mjs +259 -0
- package/dist/ui/src/components/auto-form/index.cjs +92 -0
- package/dist/ui/src/components/auto-form/index.mjs +86 -0
- package/dist/ui/src/components/auto-form/stepped-auto-form.cjs +374 -0
- package/dist/ui/src/components/auto-form/stepped-auto-form.mjs +368 -0
- package/dist/ui/src/components/auto-form/types.cjs +11 -0
- package/dist/ui/src/components/auto-form/types.mjs +9 -0
- package/dist/ui/src/components/badge.cjs +42 -0
- package/dist/ui/src/components/badge.mjs +39 -0
- package/dist/ui/src/components/button.cjs +56 -0
- package/dist/ui/src/components/button.mjs +53 -0
- package/dist/ui/src/components/calendar.cjs +207 -0
- package/dist/ui/src/components/calendar.mjs +190 -0
- package/dist/ui/src/components/card.cjs +56 -0
- package/dist/ui/src/components/card.mjs +51 -0
- package/dist/ui/src/components/checkbox.cjs +48 -0
- package/dist/ui/src/components/checkbox.mjs +32 -0
- package/dist/ui/src/components/command.cjs +78 -0
- package/dist/ui/src/components/command.mjs +73 -0
- package/dist/ui/src/components/date-picker.cjs +41 -0
- package/dist/ui/src/components/date-picker.mjs +39 -0
- package/dist/ui/src/components/dialog.cjs +119 -0
- package/dist/ui/src/components/dialog.mjs +97 -0
- package/dist/ui/src/components/form.cjs +120 -0
- package/dist/ui/src/components/form.mjs +98 -0
- package/dist/ui/src/components/input.cjs +23 -0
- package/dist/ui/src/components/input.mjs +21 -0
- package/dist/ui/src/components/label.cjs +39 -0
- package/dist/ui/src/components/label.mjs +23 -0
- package/dist/ui/src/components/multi-select.cjs +555 -0
- package/dist/ui/src/components/multi-select.mjs +540 -0
- package/dist/ui/src/components/page-layout.cjs +25 -0
- package/dist/ui/src/components/page-layout.mjs +23 -0
- package/dist/ui/src/components/page-wrapper.cjs +20 -0
- package/dist/ui/src/components/page-wrapper.mjs +18 -0
- package/dist/ui/src/components/popover.cjs +60 -0
- package/dist/ui/src/components/popover.mjs +42 -0
- package/dist/ui/src/components/radio-group.cjs +62 -0
- package/dist/ui/src/components/radio-group.mjs +45 -0
- package/dist/ui/src/components/select.cjs +161 -0
- package/dist/ui/src/components/select.mjs +139 -0
- package/dist/ui/src/components/separator.cjs +43 -0
- package/dist/ui/src/components/separator.mjs +27 -0
- package/dist/ui/src/components/skeleton.cjs +17 -0
- package/dist/ui/src/components/skeleton.mjs +15 -0
- package/dist/ui/src/components/stack-attribution.cjs +24 -0
- package/dist/ui/src/components/stack-attribution.mjs +22 -0
- package/dist/ui/src/components/switch.cjs +48 -0
- package/dist/ui/src/components/switch.mjs +32 -0
- package/dist/ui/src/components/table.cjs +89 -0
- package/dist/ui/src/components/table.mjs +82 -0
- package/dist/ui/src/components/textarea.cjs +20 -0
- package/dist/ui/src/components/textarea.mjs +18 -0
- package/dist/ui/src/hooks/use-debounce.cjs +16 -0
- package/dist/ui/src/hooks/use-debounce.mjs +14 -0
- package/dist/ui/src/hooks/use-route-lifecycle.cjs +31 -0
- package/dist/ui/src/hooks/use-route-lifecycle.mjs +29 -0
- package/dist/ui/src/lib/schema-converter.cjs +133 -0
- package/dist/ui/src/lib/schema-converter.mjs +127 -0
- package/dist/ui/src/lib/utils.cjs +10 -0
- package/dist/ui/src/lib/utils.mjs +8 -0
- package/dist/utils.cjs +19 -0
- package/dist/utils.mjs +12 -0
- package/package.json +170 -3
- package/README.md +0 -3
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for a content type defined by the developer.
|
|
5
|
+
*
|
|
6
|
+
* Field types are now specified directly in the Zod schema via .meta():
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const ProductSchema = z.object({
|
|
10
|
+
* description: z.string().meta({ fieldType: "textarea" }),
|
|
11
|
+
* image: z.string().optional().meta({ fieldType: "file" }),
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
interface ContentTypeConfig {
|
|
16
|
+
/** Display name for the content type (e.g., "Product", "Testimonial") */
|
|
17
|
+
name: string;
|
|
18
|
+
/** URL-friendly slug (e.g., "product", "testimonial") */
|
|
19
|
+
slug: string;
|
|
20
|
+
/** Optional description shown in the admin UI */
|
|
21
|
+
description?: string;
|
|
22
|
+
/** Zod schema defining the content type's fields. Use .meta({ fieldType: "..." }) for field type overrides. */
|
|
23
|
+
schema: z.ZodObject<z.ZodRawShape>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Content type stored in the database
|
|
27
|
+
*/
|
|
28
|
+
type ContentType = {
|
|
29
|
+
id: string;
|
|
30
|
+
/** Display name */
|
|
31
|
+
name: string;
|
|
32
|
+
/** URL-friendly slug - unique identifier */
|
|
33
|
+
slug: string;
|
|
34
|
+
/** Optional description */
|
|
35
|
+
description?: string;
|
|
36
|
+
/** JSON Schema representation of the Zod schema (stringified) */
|
|
37
|
+
jsonSchema: string;
|
|
38
|
+
/** @deprecated Legacy field config - now embedded in jsonSchema. Kept for backwards compat. */
|
|
39
|
+
fieldConfig?: string;
|
|
40
|
+
/** AutoForm schema version. 1 = legacy (separate fieldConfig), 2 = unified (fieldType in jsonSchema) */
|
|
41
|
+
autoFormVersion?: number;
|
|
42
|
+
createdAt: Date;
|
|
43
|
+
updatedAt: Date;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Content item stored in the database
|
|
47
|
+
*/
|
|
48
|
+
type ContentItem = {
|
|
49
|
+
id: string;
|
|
50
|
+
/** Reference to the content type */
|
|
51
|
+
contentTypeId: string;
|
|
52
|
+
/** URL-friendly slug - unique within content type */
|
|
53
|
+
slug: string;
|
|
54
|
+
/** JSON data matching the content type's schema (stringified) */
|
|
55
|
+
data: string;
|
|
56
|
+
/** Optional author ID for tracking who created/modified */
|
|
57
|
+
authorId?: string;
|
|
58
|
+
createdAt: Date;
|
|
59
|
+
updatedAt: Date;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Content item with its content type joined
|
|
63
|
+
*/
|
|
64
|
+
type ContentItemWithType = ContentItem & {
|
|
65
|
+
contentType?: ContentType;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Content relation stored in the database (junction table)
|
|
69
|
+
* Links source content items to target content items for relationship fields
|
|
70
|
+
*/
|
|
71
|
+
type ContentRelation = {
|
|
72
|
+
id: string;
|
|
73
|
+
/** The content item that has the relation field */
|
|
74
|
+
sourceId: string;
|
|
75
|
+
/** The content item being referenced */
|
|
76
|
+
targetId: string;
|
|
77
|
+
/** The field name in the source content type schema (e.g., "categoryIds") */
|
|
78
|
+
fieldName: string;
|
|
79
|
+
createdAt: Date;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Configuration for a relation field in schema metadata.
|
|
83
|
+
* Use with .meta({ fieldType: "relation", relation: {...} })
|
|
84
|
+
*
|
|
85
|
+
* The schema stores relation values as simple `{ id: string }` references.
|
|
86
|
+
* When `creatable: true`, the frontend sends `{ _new: true, data: {...} }`
|
|
87
|
+
* which the API processes before validation - creating new items and
|
|
88
|
+
* converting them to ID references.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* const ResourceSchema = z.object({
|
|
93
|
+
* // Simple array of ID references - API handles _new items before validation
|
|
94
|
+
* categoryIds: z.array(z.object({ id: z.string() })).default([]).meta({
|
|
95
|
+
* fieldType: "relation",
|
|
96
|
+
* relation: {
|
|
97
|
+
* type: "manyToMany",
|
|
98
|
+
* targetType: "category",
|
|
99
|
+
* displayField: "name",
|
|
100
|
+
* creatable: true,
|
|
101
|
+
* },
|
|
102
|
+
* }),
|
|
103
|
+
* });
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
interface RelationConfig {
|
|
107
|
+
/** Relation type */
|
|
108
|
+
type: "belongsTo" | "hasMany" | "manyToMany";
|
|
109
|
+
/** Target content type slug */
|
|
110
|
+
targetType: string;
|
|
111
|
+
/** Field to display in the dropdown (e.g., "name", "title") */
|
|
112
|
+
displayField: string;
|
|
113
|
+
/** Allow creating new items inline via modal (default: false) */
|
|
114
|
+
creatable?: boolean;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Value for a relation field - either a reference to existing item or a new item to create.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```typescript
|
|
121
|
+
* // Reference to existing item
|
|
122
|
+
* const existing: RelationValue = { id: "abc123" };
|
|
123
|
+
*
|
|
124
|
+
* // New item to create on save
|
|
125
|
+
* const newItem: RelationValue = {
|
|
126
|
+
* _new: true,
|
|
127
|
+
* data: { name: "New Category", description: "..." }
|
|
128
|
+
* };
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
type RelationValue = {
|
|
132
|
+
id: string;
|
|
133
|
+
} | {
|
|
134
|
+
_new: true;
|
|
135
|
+
data: Record<string, unknown>;
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Represents an inverse relation (content types that reference this type via belongsTo)
|
|
139
|
+
*/
|
|
140
|
+
interface InverseRelation {
|
|
141
|
+
/** The content type slug that has the belongsTo relation */
|
|
142
|
+
sourceType: string;
|
|
143
|
+
/** Display name of the source content type */
|
|
144
|
+
sourceTypeName: string;
|
|
145
|
+
/** The field name that contains the belongsTo relation */
|
|
146
|
+
fieldName: string;
|
|
147
|
+
/** Count of items with this relation (when itemId is provided) */
|
|
148
|
+
count: number;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Serialized content type for API responses (dates as strings)
|
|
152
|
+
*/
|
|
153
|
+
interface SerializedContentType extends Omit<ContentType, "createdAt" | "updatedAt"> {
|
|
154
|
+
createdAt: string;
|
|
155
|
+
updatedAt: string;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Serialized content item for API responses (dates as strings)
|
|
159
|
+
*/
|
|
160
|
+
interface SerializedContentItem extends Omit<ContentItem, "createdAt" | "updatedAt"> {
|
|
161
|
+
createdAt: string;
|
|
162
|
+
updatedAt: string;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Serialized content item with parsed data and joined content type
|
|
166
|
+
* @template TData - The type of the parsed data (defaults to Record<string, unknown>)
|
|
167
|
+
*/
|
|
168
|
+
interface SerializedContentItemWithType<TData = Record<string, unknown>> extends SerializedContentItem {
|
|
169
|
+
/** Parsed data object (JSON.parse of data field). */
|
|
170
|
+
parsedData: TData;
|
|
171
|
+
/** Joined content type */
|
|
172
|
+
contentType?: SerializedContentType;
|
|
173
|
+
/**
|
|
174
|
+
* Populated relation data (only present when using populated endpoints/hooks).
|
|
175
|
+
* Keys are field names, values are arrays of related content items.
|
|
176
|
+
*/
|
|
177
|
+
_relations?: Record<string, SerializedContentItemWithType[]>;
|
|
178
|
+
}
|
|
179
|
+
/** Output shape for CMS reads; omission retains the full editor envelope. */
|
|
180
|
+
type CMSReadView = "content" | undefined;
|
|
181
|
+
/** Literal top-level property names selected from parsed content. */
|
|
182
|
+
type CMSContentFields = readonly string[] | undefined;
|
|
183
|
+
/** Select known literal properties, or an honest partial shape for dynamic arrays. */
|
|
184
|
+
type CMSSelectedData<TData, TFields extends CMSContentFields = undefined> = TFields extends readonly string[] ? string extends TFields[number] ? Partial<TData> : Pick<TData, Extract<TFields[number], keyof TData>> : TData;
|
|
185
|
+
/** Optional output controls for CMS reads. These do not change access checks. */
|
|
186
|
+
interface CMSReadOptions<TView extends CMSReadView = CMSReadView, TFields extends CMSContentFields = CMSContentFields> {
|
|
187
|
+
/** Return identity, parsed content and timestamps without editor metadata. */
|
|
188
|
+
view?: TView;
|
|
189
|
+
/** Literal declared top-level content properties. Requires content view. */
|
|
190
|
+
fields?: TFields;
|
|
191
|
+
}
|
|
192
|
+
/** Serialized content envelope without raw JSON or editor metadata. */
|
|
193
|
+
type SerializedContentItemContent<TData = Record<string, unknown>> = Pick<SerializedContentItemWithType<TData>, "id" | "slug" | "parsedData" | "createdAt" | "updatedAt">;
|
|
194
|
+
/** Result envelope selected by a statically known read view. */
|
|
195
|
+
type CMSContentItemResult<TData = Record<string, unknown>, TView extends CMSReadView = undefined, TFields extends CMSContentFields = undefined> = TView extends "content" ? SerializedContentItemContent<CMSSelectedData<TData, TFields>> : SerializedContentItemWithType<TData>;
|
|
196
|
+
/**
|
|
197
|
+
* Paginated list response for content items
|
|
198
|
+
* @template TData - The type of the parsed data (defaults to Record<string, unknown>)
|
|
199
|
+
*/
|
|
200
|
+
interface PaginatedContentItems<TData = Record<string, unknown>, TView extends CMSReadView = undefined, TFields extends CMSContentFields = undefined> {
|
|
201
|
+
items: CMSContentItemResult<TData, TView, TFields>[];
|
|
202
|
+
total: number;
|
|
203
|
+
limit: number;
|
|
204
|
+
offset: number;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Type helper to define a map of content type slugs to their data types.
|
|
208
|
+
* Use with z.infer to get the type from your Zod schemas.
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```typescript
|
|
212
|
+
* import { z } from "zod"
|
|
213
|
+
*
|
|
214
|
+
* // Define your schemas
|
|
215
|
+
* export const ProductSchema = z.object({
|
|
216
|
+
* name: z.string(),
|
|
217
|
+
* price: z.number(),
|
|
218
|
+
* })
|
|
219
|
+
*
|
|
220
|
+
* export const TestimonialSchema = z.object({
|
|
221
|
+
* author: z.string(),
|
|
222
|
+
* quote: z.string(),
|
|
223
|
+
* })
|
|
224
|
+
*
|
|
225
|
+
* // Create the type map
|
|
226
|
+
* export type MyCMSTypes = {
|
|
227
|
+
* product: z.infer<typeof ProductSchema>
|
|
228
|
+
* testimonial: z.infer<typeof TestimonialSchema>
|
|
229
|
+
* }
|
|
230
|
+
*
|
|
231
|
+
* // Use in hooks for type-safe parsedData
|
|
232
|
+
* const { items } = useContent<MyCMSTypes, "product">("product")
|
|
233
|
+
* // items[0].parsedData.name is typed as string
|
|
234
|
+
* // items[0].parsedData.price is typed as number
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
type CMSContentTypeMap = Record<string, Record<string, unknown>>;
|
|
238
|
+
/** JSON-safe values accepted at the CMS operation boundary. */
|
|
239
|
+
type CMSOperationData = string | number | boolean | null | readonly CMSOperationData[] | {
|
|
240
|
+
readonly [key: string]: CMSOperationData;
|
|
241
|
+
};
|
|
242
|
+
/** @deprecated Use the operation-specific CMS lifecycle contexts instead. */
|
|
243
|
+
interface CMSHookContext {
|
|
244
|
+
readonly typeSlug: string;
|
|
245
|
+
readonly userId?: string;
|
|
246
|
+
readonly headers?: Headers;
|
|
247
|
+
}
|
|
248
|
+
interface CMSOperationIdentity {
|
|
249
|
+
readonly id: string;
|
|
250
|
+
readonly [key: string]: unknown;
|
|
251
|
+
}
|
|
252
|
+
type CMSDeepReadonly<T> = T extends (...args: any[]) => unknown ? T : T extends readonly unknown[] ? {
|
|
253
|
+
readonly [TKey in keyof T]: CMSDeepReadonly<T[TKey]>;
|
|
254
|
+
} : T extends object ? {
|
|
255
|
+
readonly [TKey in keyof T]: CMSDeepReadonly<T[TKey]>;
|
|
256
|
+
} : T;
|
|
257
|
+
interface CMSOperationContextBase<TInput, TFacts> {
|
|
258
|
+
/** Validated, deeply readonly input supplied to the operation. */
|
|
259
|
+
readonly input: Readonly<TInput>;
|
|
260
|
+
/** Trusted server-derived facts used by the authorization rule. */
|
|
261
|
+
readonly facts: Readonly<TFacts>;
|
|
262
|
+
/** Authorized request identity, or `null` for anonymous and trusted calls. */
|
|
263
|
+
readonly identity: Readonly<CMSOperationIdentity> | null;
|
|
264
|
+
/** Transport request when the operation was invoked through HTTP or `forRequest()`. */
|
|
265
|
+
readonly request?: Request;
|
|
266
|
+
/** Compatibility view of the transport request headers. */
|
|
267
|
+
readonly headers?: Headers;
|
|
268
|
+
/** Compatibility alias for the authorized identity ID. */
|
|
269
|
+
readonly userId?: string;
|
|
270
|
+
/** Compatibility alias for the operation's CMS content-type slug. */
|
|
271
|
+
readonly typeSlug?: string;
|
|
272
|
+
}
|
|
273
|
+
/** Authorized context supplied before a CMS record is created. */
|
|
274
|
+
interface CMSCreateOperationContext extends CMSOperationContextBase<{
|
|
275
|
+
readonly typeSlug: string;
|
|
276
|
+
readonly body: {
|
|
277
|
+
readonly slug: string;
|
|
278
|
+
readonly data: Readonly<Record<string, CMSOperationData>>;
|
|
279
|
+
};
|
|
280
|
+
}, {
|
|
281
|
+
contentType: string;
|
|
282
|
+
}> {
|
|
283
|
+
/** Server-resolved content-type slug for the record being created. */
|
|
284
|
+
readonly typeSlug: string;
|
|
285
|
+
/** Validated create payload supplied to the operation. */
|
|
286
|
+
readonly body: {
|
|
287
|
+
/** Requested record slug before canonical slugification. */
|
|
288
|
+
readonly slug: string;
|
|
289
|
+
/** Validated JSON-safe request fields, including any inline `_new` relation values. */
|
|
290
|
+
readonly data: Readonly<Record<string, CMSOperationData>>;
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/** CMS create context after execution. */
|
|
294
|
+
interface CMSCreateResultContext extends CMSCreateOperationContext {
|
|
295
|
+
/** Fully serialized record returned by the successful create operation. */
|
|
296
|
+
readonly result: CMSDeepReadonly<SerializedContentItemWithType>;
|
|
297
|
+
}
|
|
298
|
+
/** Authorized context supplied before a CMS record is updated. */
|
|
299
|
+
interface CMSUpdateOperationContext extends CMSOperationContextBase<{
|
|
300
|
+
readonly typeSlug: string;
|
|
301
|
+
readonly id: string;
|
|
302
|
+
readonly body: {
|
|
303
|
+
readonly slug?: string;
|
|
304
|
+
readonly data?: Readonly<Record<string, CMSOperationData>>;
|
|
305
|
+
};
|
|
306
|
+
}, {
|
|
307
|
+
contentType: string;
|
|
308
|
+
recordId: string;
|
|
309
|
+
authorId?: string;
|
|
310
|
+
}> {
|
|
311
|
+
/** Server-resolved content-type slug for the record being updated. */
|
|
312
|
+
readonly typeSlug: string;
|
|
313
|
+
/** Canonical route parameters for the authorized record. */
|
|
314
|
+
readonly params: {
|
|
315
|
+
readonly typeSlug: string;
|
|
316
|
+
readonly id: string;
|
|
317
|
+
};
|
|
318
|
+
/** Validated partial update payload supplied to the operation. */
|
|
319
|
+
readonly body: {
|
|
320
|
+
/** Optional replacement slug before canonical slugification. */
|
|
321
|
+
readonly slug?: string;
|
|
322
|
+
/** Optional record-field fragment; hooks receive its merged validated result. */
|
|
323
|
+
readonly data?: Readonly<Record<string, CMSOperationData>>;
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
/** CMS update context after execution. */
|
|
327
|
+
interface CMSUpdateResultContext extends CMSUpdateOperationContext {
|
|
328
|
+
/** Fully serialized record returned by the successful update operation. */
|
|
329
|
+
readonly result: CMSDeepReadonly<SerializedContentItemWithType>;
|
|
330
|
+
}
|
|
331
|
+
/** Authorized context supplied before a CMS record is deleted. */
|
|
332
|
+
interface CMSDeleteOperationContext extends CMSOperationContextBase<{
|
|
333
|
+
readonly typeSlug: string;
|
|
334
|
+
readonly id: string;
|
|
335
|
+
}, {
|
|
336
|
+
contentType: string;
|
|
337
|
+
recordId: string;
|
|
338
|
+
authorId?: string;
|
|
339
|
+
}> {
|
|
340
|
+
/** Server-resolved content-type slug for the record being deleted. */
|
|
341
|
+
readonly typeSlug: string;
|
|
342
|
+
/** Canonical route parameters for the authorized record. */
|
|
343
|
+
readonly params: {
|
|
344
|
+
readonly typeSlug: string;
|
|
345
|
+
readonly id: string;
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
/** CMS delete context after execution. */
|
|
349
|
+
interface CMSDeleteResultContext extends CMSDeleteOperationContext {
|
|
350
|
+
/** Successful delete result. */
|
|
351
|
+
readonly result: {
|
|
352
|
+
readonly success: true;
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
interface CMSReadOperationContext extends CMSOperationContextBase<unknown, {
|
|
356
|
+
contentType?: string;
|
|
357
|
+
scope?: "collection" | "record";
|
|
358
|
+
recordId?: string;
|
|
359
|
+
authorId?: string;
|
|
360
|
+
}> {
|
|
361
|
+
}
|
|
362
|
+
/** Authorized context shared by the CMS operation lifecycle hooks. */
|
|
363
|
+
type CMSOperationLifecycleContext = CMSReadOperationContext | CMSCreateOperationContext | CMSUpdateOperationContext | CMSDeleteOperationContext;
|
|
364
|
+
/** Authorized lifecycle context supplied to the observational error hook. */
|
|
365
|
+
type CMSOperationErrorContext = CMSOperationLifecycleContext & {
|
|
366
|
+
/** Original post-authorization operation error observed by `onErrorExecuteContentOperation`. */
|
|
367
|
+
readonly error: unknown;
|
|
368
|
+
};
|
|
369
|
+
/** Domain lifecycle hooks that run only after successful CMS authorization. */
|
|
370
|
+
interface CMSBackendHooks {
|
|
371
|
+
/** Runs with validated canonical record data after authorization and before any database write. */
|
|
372
|
+
onBeforeCreateContent?: (data: Readonly<Record<string, CMSOperationData>>, context: CMSCreateOperationContext) => Promise<void> | void;
|
|
373
|
+
/** Observes the fully created record after the atomic create succeeds. */
|
|
374
|
+
onAfterCreateContent?: (item: CMSDeepReadonly<SerializedContentItemWithType>, context: CMSCreateResultContext) => Promise<void> | void;
|
|
375
|
+
/** Runs for every update with the complete merged, validated record before any database write. */
|
|
376
|
+
onBeforeUpdateContent?: (id: string, data: Readonly<Record<string, CMSOperationData>>, context: CMSUpdateOperationContext) => Promise<void> | void;
|
|
377
|
+
/** Observes the fully updated record after the atomic update succeeds. */
|
|
378
|
+
onAfterUpdateContent?: (item: CMSDeepReadonly<SerializedContentItemWithType>, context: CMSUpdateResultContext) => Promise<void> | void;
|
|
379
|
+
/** Runs after authorization and before the record is deleted. */
|
|
380
|
+
onBeforeDeleteContent?: (id: string, context: CMSDeleteOperationContext) => Promise<void> | void;
|
|
381
|
+
/** Observes the deleted record ID after the atomic delete succeeds. */
|
|
382
|
+
onAfterDeleteContent?: (id: string, context: CMSDeleteResultContext) => Promise<void> | void;
|
|
383
|
+
/** Observes post-authorization failures without replacing the original error. */
|
|
384
|
+
onErrorExecuteContentOperation?: (error: Error, operation: "create" | "update" | "delete" | "list" | "get", context: CMSOperationErrorContext) => Promise<void> | void;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Configuration for the CMS backend plugin
|
|
388
|
+
*/
|
|
389
|
+
interface CMSBackendConfig {
|
|
390
|
+
/** Content types defined by the developer */
|
|
391
|
+
contentTypes: ContentTypeConfig[];
|
|
392
|
+
/** Optional hooks for customizing behavior */
|
|
393
|
+
hooks?: CMSBackendHooks;
|
|
394
|
+
/**
|
|
395
|
+
* Maximum number of items that can be requested in a single page.
|
|
396
|
+
* Applied to all list endpoints (`/content/:typeSlug`, by-relation, and inverse-relation).
|
|
397
|
+
*
|
|
398
|
+
* Raise this when your content types have many items and you need to fetch
|
|
399
|
+
* large pages (e.g. for SSG, CSV export, or programmatic access).
|
|
400
|
+
*
|
|
401
|
+
* @default 1000
|
|
402
|
+
*/
|
|
403
|
+
maxPageSize?: number;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export type { CMSBackendConfig, CMSBackendHooks, CMSContentFields, CMSContentItemResult, CMSContentTypeMap, CMSCreateOperationContext, CMSCreateResultContext, CMSDeleteOperationContext, CMSDeleteResultContext, CMSHookContext, CMSOperationData, CMSOperationErrorContext, CMSOperationLifecycleContext, CMSReadOptions, CMSReadView, CMSSelectedData, CMSUpdateOperationContext, CMSUpdateResultContext, ContentItem, ContentItemWithType, ContentRelation, ContentType, ContentTypeConfig, InverseRelation, PaginatedContentItems, RelationConfig, RelationValue, SerializedContentItem, SerializedContentItemContent, SerializedContentItemWithType, SerializedContentType };
|
package/dist/types.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
const AccordionPrimitive = require('@radix-ui/react-accordion');
|
|
6
|
+
const lucideReact = require('lucide-react');
|
|
7
|
+
const utils = require('../lib/utils.cjs');
|
|
8
|
+
|
|
9
|
+
function _interopNamespaceCompat(e) {
|
|
10
|
+
if (e && typeof e === 'object' && 'default' in e) return e;
|
|
11
|
+
const n = Object.create(null);
|
|
12
|
+
if (e) {
|
|
13
|
+
for (const k in e) {
|
|
14
|
+
n[k] = e[k];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
n.default = e;
|
|
18
|
+
return n;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const AccordionPrimitive__namespace = /*#__PURE__*/_interopNamespaceCompat(AccordionPrimitive);
|
|
22
|
+
|
|
23
|
+
function Accordion({
|
|
24
|
+
...props
|
|
25
|
+
}) {
|
|
26
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AccordionPrimitive__namespace.Root, { "data-slot": "accordion", ...props });
|
|
27
|
+
}
|
|
28
|
+
function AccordionItem({
|
|
29
|
+
className,
|
|
30
|
+
...props
|
|
31
|
+
}) {
|
|
32
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
33
|
+
AccordionPrimitive__namespace.Item,
|
|
34
|
+
{
|
|
35
|
+
"data-slot": "accordion-item",
|
|
36
|
+
className: utils.cn("border-b last:border-b-0", className),
|
|
37
|
+
...props
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
function AccordionTrigger({
|
|
42
|
+
className,
|
|
43
|
+
children,
|
|
44
|
+
...props
|
|
45
|
+
}) {
|
|
46
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AccordionPrimitive__namespace.Header, { className: "flex", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
47
|
+
AccordionPrimitive__namespace.Trigger,
|
|
48
|
+
{
|
|
49
|
+
"data-slot": "accordion-trigger",
|
|
50
|
+
className: utils.cn(
|
|
51
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
|
|
52
|
+
className
|
|
53
|
+
),
|
|
54
|
+
...props,
|
|
55
|
+
children: [
|
|
56
|
+
children,
|
|
57
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" })
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
) });
|
|
61
|
+
}
|
|
62
|
+
function AccordionContent({
|
|
63
|
+
className,
|
|
64
|
+
children,
|
|
65
|
+
...props
|
|
66
|
+
}) {
|
|
67
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
68
|
+
AccordionPrimitive__namespace.Content,
|
|
69
|
+
{
|
|
70
|
+
"data-slot": "accordion-content",
|
|
71
|
+
className: "data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm",
|
|
72
|
+
...props,
|
|
73
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: utils.cn("pt-0 pb-4", className), children })
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
exports.Accordion = Accordion;
|
|
79
|
+
exports.AccordionContent = AccordionContent;
|
|
80
|
+
exports.AccordionItem = AccordionItem;
|
|
81
|
+
exports.AccordionTrigger = AccordionTrigger;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
|
4
|
+
import { ChevronDownIcon } from 'lucide-react';
|
|
5
|
+
import { cn } from '../lib/utils.mjs';
|
|
6
|
+
|
|
7
|
+
function Accordion({
|
|
8
|
+
...props
|
|
9
|
+
}) {
|
|
10
|
+
return /* @__PURE__ */ jsx(AccordionPrimitive.Root, { "data-slot": "accordion", ...props });
|
|
11
|
+
}
|
|
12
|
+
function AccordionItem({
|
|
13
|
+
className,
|
|
14
|
+
...props
|
|
15
|
+
}) {
|
|
16
|
+
return /* @__PURE__ */ jsx(
|
|
17
|
+
AccordionPrimitive.Item,
|
|
18
|
+
{
|
|
19
|
+
"data-slot": "accordion-item",
|
|
20
|
+
className: cn("border-b last:border-b-0", className),
|
|
21
|
+
...props
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
function AccordionTrigger({
|
|
26
|
+
className,
|
|
27
|
+
children,
|
|
28
|
+
...props
|
|
29
|
+
}) {
|
|
30
|
+
return /* @__PURE__ */ jsx(AccordionPrimitive.Header, { className: "flex", children: /* @__PURE__ */ jsxs(
|
|
31
|
+
AccordionPrimitive.Trigger,
|
|
32
|
+
{
|
|
33
|
+
"data-slot": "accordion-trigger",
|
|
34
|
+
className: cn(
|
|
35
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
|
|
36
|
+
className
|
|
37
|
+
),
|
|
38
|
+
...props,
|
|
39
|
+
children: [
|
|
40
|
+
children,
|
|
41
|
+
/* @__PURE__ */ jsx(ChevronDownIcon, { className: "text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" })
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
) });
|
|
45
|
+
}
|
|
46
|
+
function AccordionContent({
|
|
47
|
+
className,
|
|
48
|
+
children,
|
|
49
|
+
...props
|
|
50
|
+
}) {
|
|
51
|
+
return /* @__PURE__ */ jsx(
|
|
52
|
+
AccordionPrimitive.Content,
|
|
53
|
+
{
|
|
54
|
+
"data-slot": "accordion-content",
|
|
55
|
+
className: "data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm",
|
|
56
|
+
...props,
|
|
57
|
+
children: /* @__PURE__ */ jsx("div", { className: cn("pt-0 pb-4", className), children })
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
|