@nextblock-cms/cortex 0.20.1 → 0.21.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 (71) hide show
  1. package/client.cjs.js +1 -1
  2. package/client.es.js +3 -7
  3. package/index.cjs.js +1 -1
  4. package/index.es.js +24 -277
  5. package/lib/ai-block-generation.cjs.js +3 -4
  6. package/lib/ai-block-generation.es.js +143 -182
  7. package/lib/ai-client.cjs.js +1 -1
  8. package/lib/ai-client.d.ts +1 -1
  9. package/lib/ai-client.es.js +101 -135
  10. package/lib/ai-config.cjs.js +1 -1
  11. package/lib/ai-config.es.js +89 -108
  12. package/lib/ai-cortex-widget-builder.cjs.js +1 -1
  13. package/lib/ai-cortex-widget-builder.es.js +56 -70
  14. package/lib/ai-global-agent-content-ops-tools.cjs.js +1 -1
  15. package/lib/ai-global-agent-content-ops-tools.d.ts +1943 -68
  16. package/lib/ai-global-agent-content-ops-tools.es.js +185 -199
  17. package/lib/ai-global-agent-custom-block-tools.cjs.js +1 -1
  18. package/lib/ai-global-agent-custom-block-tools.d.ts +2160 -95
  19. package/lib/ai-global-agent-custom-block-tools.es.js +226 -223
  20. package/lib/ai-global-agent-db-tools.cjs.js +1 -1
  21. package/lib/ai-global-agent-db-tools.d.ts +2708 -98
  22. package/lib/ai-global-agent-db-tools.es.js +1013 -986
  23. package/lib/ai-global-agent-ecommerce.cjs.js +1 -1
  24. package/lib/ai-global-agent-ecommerce.es.js +3 -7
  25. package/lib/ai-global-agent-site-tools.cjs.js +2 -3
  26. package/lib/ai-global-agent-site-tools.d.ts +10695 -500
  27. package/lib/ai-global-agent-site-tools.es.js +750 -757
  28. package/lib/ai-global-agent-theming-tools.cjs.js +1 -3
  29. package/lib/ai-global-agent-theming-tools.d.ts +2905 -105
  30. package/lib/ai-global-agent-theming-tools.es.js +326 -396
  31. package/lib/ai-global-agent-tools.cjs.js +2 -2
  32. package/lib/ai-global-agent-tools.d.ts +4 -2230
  33. package/lib/ai-global-agent-tools.es.js +3899 -4328
  34. package/lib/ai-key-crypto.cjs.js +1 -1
  35. package/lib/ai-key-crypto.es.js +63 -82
  36. package/lib/ai-key-verification.cjs.js +1 -1
  37. package/lib/ai-key-verification.es.js +74 -63
  38. package/lib/ai-model-catalog.cjs.js +1 -1
  39. package/lib/ai-model-catalog.es.js +18 -22
  40. package/lib/ai-model-registry.cjs.js +2 -2
  41. package/lib/ai-model-registry.es.js +246 -309
  42. package/lib/ai-seo-metadata.cjs.js +2 -3
  43. package/lib/ai-seo-metadata.es.js +143 -185
  44. package/lib/ai-vision.cjs.js +2 -2
  45. package/lib/ai-vision.d.ts +6 -6
  46. package/lib/ai-vision.es.js +161 -215
  47. package/lib/block-content-schemas.cjs.js +1 -1
  48. package/lib/block-content-schemas.es.js +324 -254
  49. package/lib/cortex-widget-registry.cjs.js +1 -1
  50. package/lib/cortex-widget-registry.es.js +35 -43
  51. package/lib/cortex-widget-schema.cjs.js +2 -3
  52. package/lib/cortex-widget-schema.es.js +280 -309
  53. package/lib/editor-document-from-html.cjs.js +1 -1
  54. package/lib/editor-document-from-html.es.js +334 -278
  55. package/lib/fetch-host-guard.cjs.js +1 -0
  56. package/lib/fetch-host-guard.d.ts +2 -0
  57. package/lib/fetch-host-guard.es.js +30 -0
  58. package/lib/mcp-server.cjs.js +1 -1
  59. package/lib/mcp-server.es.js +155 -173
  60. package/lib/mcp-tokens.cjs.js +1 -1
  61. package/lib/mcp-tokens.es.js +95 -107
  62. package/lib/mcp-tool-registry.cjs.js +5 -6
  63. package/lib/mcp-tool-registry.es.js +533 -411
  64. package/lib/site-brief.cjs.js +2 -2
  65. package/lib/site-brief.es.js +102 -108
  66. package/lib/vision-image-download.cjs.js +1 -0
  67. package/lib/vision-image-download.d.ts +43 -0
  68. package/lib/vision-image-download.es.js +120 -0
  69. package/lib/zod-config.cjs.js +1 -1
  70. package/lib/zod-config.es.js +5 -6
  71. package/package.json +8 -8
@@ -1,262 +1,332 @@
1
- import "./zod-config.es.js";
2
- import { z as t } from "zod";
3
- const d = [
4
- "text",
5
- "heading",
6
- "image",
7
- "button",
8
- "posts_grid",
9
- "video_embed",
10
- "section",
11
- "form",
12
- "testimonial",
13
- "product_grid",
14
- "featured_product",
15
- "cart",
16
- "checkout",
17
- "product_details"
18
- ], b = t.enum(d), m = t.object({
19
- direction: t.string().optional(),
20
- stops: t.array(t.object({ color: t.string(), position: t.number() })),
21
- type: t.enum(["linear", "radial"])
22
- }), g = t.object({
23
- gradient: m.optional(),
24
- image: t.object({
25
- alt_text: t.string().optional(),
26
- blur_data_url: t.string().optional(),
27
- external_url: t.string().optional(),
28
- height: t.number().optional(),
29
- media_id: t.string().optional(),
30
- object_key: t.string().optional(),
31
- overlay: t.object({
32
- gradient: m,
33
- type: t.literal("gradient")
34
- }).optional(),
35
- position: t.enum(["center", "top", "bottom", "left", "right"]),
36
- quality: t.number().nullable().optional(),
37
- size: t.enum(["cover", "contain"]),
38
- width: t.number().optional()
39
- }).optional(),
40
- min_height: t.string().optional(),
41
- solid_color: t.string().optional(),
42
- theme: t.enum(["primary", "secondary", "muted", "accent", "destructive"]).optional(),
43
- type: t.enum(["none", "theme", "solid", "gradient", "image"])
44
- }), f = t.string().regex(/^[a-z][a-z0-9-]*$/), p = t.object({
45
- block_type: t.union([b, f]),
46
- content: t.record(t.string(), t.any()),
47
- temp_id: t.string().optional()
48
- }), y = t.object({
49
- background: g,
50
- column_blocks: t.array(t.array(p))
51
- }), h = t.object({
52
- // Slider settings mirror the editor's "Enable Slider (Carousel layout)" panel:
53
- // `autoplay` rotates the slides every `timeframe` SECONDS (5 when omitted).
54
- autoplay: t.boolean().optional(),
55
- background: g,
56
- column_blocks: t.array(t.array(p)),
57
- column_gap: t.enum(["none", "sm", "md", "lg", "xl"]),
58
- container_type: t.enum(["full-width", "container", "container-sm", "container-lg", "container-xl"]),
59
- // The editor's "Hero Section (Prioritized image loading)" checkbox: the section's
60
- // background image (and the first slide's images) load with priority, and the
61
- // normalizer centres its content vertically.
62
- is_hero: t.boolean().optional(),
63
- padding: t.object({
64
- bottom: t.enum(["none", "sm", "md", "lg", "xl"]),
65
- top: t.enum(["none", "sm", "md", "lg", "xl"])
66
- }),
67
- responsive_columns: t.object({
68
- desktop: t.union([t.literal(1), t.literal(2), t.literal(3), t.literal(4)]),
69
- mobile: t.union([t.literal(1), t.literal(2)]),
70
- tablet: t.union([t.literal(1), t.literal(2), t.literal(3)])
71
- }),
72
- // With `slider: true` and a non-empty `slides` list the renderer shows a carousel
73
- // of those slides and ignores the top-level `column_blocks` and `background`.
74
- slider: t.boolean().optional(),
75
- slides: t.array(y).optional(),
76
- timeframe: t.number().optional(),
77
- vertical_alignment: t.enum(["start", "center", "end", "stretch"]).optional()
78
- }), _ = {
79
- button: t.object({
80
- position: t.enum(["left", "center", "right"]).optional(),
81
- size: t.enum(["default", "sm", "lg", "full"]).optional(),
82
- text: t.string(),
83
- url: t.string(),
84
- variant: t.enum(["default", "outline", "secondary", "ghost", "link"]).optional()
85
- }),
86
- cart: t.object({}),
87
- checkout: t.object({}),
88
- featured_product: t.object({
89
- imagePosition: t.enum(["left", "right"]).default("left"),
90
- productId: t.string().min(1),
91
- showBackground: t.boolean().default(!1)
92
- }),
93
- form: t.object({
94
- fields: t.array(
95
- t.object({
96
- // Mirrors FormFieldSchema in apps/nextblock/lib/blocks/blockRegistry.ts.
97
- field_type: t.enum(["text", "email", "tel", "url", "number", "textarea", "select", "radio", "checkbox"]),
98
- is_required: t.boolean(),
99
- label: t.string(),
100
- options: t.array(t.object({ label: t.string(), value: t.string() })).optional(),
101
- placeholder: t.string().optional(),
102
- temp_id: t.string()
103
- })
104
- ),
105
- // Opaque handle into form_endpoints, which holds the destination server-side.
106
- form_key: t.string().optional(),
107
- // Legacy. Migration 27 moved every address out of block content; kept optional so
108
- // an older payload still validates, and stripped before the block reaches a browser.
109
- recipient_email: t.string().email().optional(),
110
- submit_button_text: t.string(),
111
- success_message: t.string()
112
- }),
113
- heading: t.object({
114
- level: t.union([t.literal(1), t.literal(2), t.literal(3), t.literal(4), t.literal(5), t.literal(6)]),
115
- textAlign: t.enum(["left", "center", "right", "justify"]).optional(),
116
- // Mirrors TextColorSchema in apps/nextblock/lib/blocks/blockRegistry.ts —
117
- // a theme token, or a literal CSS colour from the block editor's picker.
118
- // libs/* cannot import from the app, so the union is restated here.
119
- textColor: t.union([
120
- t.enum(["foreground", "primary", "secondary", "accent", "muted", "destructive", "background"]),
121
- t.string().regex(
122
- /^(#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})|rgba?\([^)]+\)|hsla?\([^)]+\))$/i,
123
- "Must be a hex, rgb(a) or hsl(a) colour"
124
- )
125
- ]).optional().describe("Prefer a theme token so the heading adapts to dark mode; use a CSS colour only when the brand requires an exact value"),
126
- text_content: t.string()
127
- }),
128
- image: t.object({
129
- alt_text: t.string().optional(),
130
- caption: t.string().optional(),
131
- external_url: t.string().nullable().optional(),
132
- height: t.number().nullable().optional(),
133
- media_id: t.string().nullable().optional(),
134
- object_key: t.string().nullable().optional(),
135
- width: t.number().nullable().optional()
136
- }),
137
- posts_grid: t.object({
138
- columns: t.number().min(1).max(6),
139
- postsPerPage: t.number().min(1).max(50),
140
- showPagination: t.boolean(),
141
- title: t.string().optional()
142
- }),
143
- product_details: t.object({}),
144
- product_grid: t.object({
145
- categoryId: t.string().optional(),
146
- categoryIds: t.array(t.string()).max(20).optional(),
147
- // 0 = unlimited (every match on one page).
148
- limit: t.number().min(0).max(48).default(6),
149
- productIds: t.array(t.string()).max(24).optional(),
150
- showPagination: t.boolean().default(!1),
151
- title: t.string().optional(),
152
- type: t.enum(["latest", "category", "manual"]).default("latest")
153
- }),
154
- section: h,
155
- testimonial: t.object({
156
- author_name: t.string().min(1),
157
- author_title: t.string().optional(),
158
- image_url: t.string().url().optional().or(t.literal("")),
159
- quote: t.string().min(1)
160
- }),
161
- text: t.object({
162
- html_content: t.string()
163
- }),
164
- video_embed: t.object({
165
- autoplay: t.boolean().optional(),
166
- controls: t.boolean().optional(),
167
- title: t.string().optional(),
168
- url: t.string()
169
- })
1
+ import { z as e } from "./zod-config.es.js";
2
+ //#region libs/cortex/src/lib/block-content-schemas.ts
3
+ var t = [
4
+ "text",
5
+ "heading",
6
+ "image",
7
+ "button",
8
+ "posts_grid",
9
+ "video_embed",
10
+ "section",
11
+ "form",
12
+ "testimonial",
13
+ "product_grid",
14
+ "featured_product",
15
+ "cart",
16
+ "checkout",
17
+ "product_details"
18
+ ], n = e.enum(t), r = e.object({
19
+ direction: e.string().optional(),
20
+ stops: e.array(e.object({
21
+ color: e.string(),
22
+ position: e.number()
23
+ })),
24
+ type: e.enum(["linear", "radial"])
25
+ }), i = e.object({
26
+ gradient: r.optional(),
27
+ image: e.object({
28
+ alt_text: e.string().optional(),
29
+ blur_data_url: e.string().optional(),
30
+ external_url: e.string().optional(),
31
+ height: e.number().optional(),
32
+ media_id: e.string().optional(),
33
+ object_key: e.string().optional(),
34
+ overlay: e.object({
35
+ gradient: r,
36
+ type: e.literal("gradient")
37
+ }).optional(),
38
+ position: e.enum([
39
+ "center",
40
+ "top",
41
+ "bottom",
42
+ "left",
43
+ "right"
44
+ ]),
45
+ quality: e.number().nullable().optional(),
46
+ size: e.enum(["cover", "contain"]),
47
+ width: e.number().optional()
48
+ }).optional(),
49
+ min_height: e.string().optional(),
50
+ solid_color: e.string().optional(),
51
+ theme: e.enum([
52
+ "primary",
53
+ "secondary",
54
+ "muted",
55
+ "accent",
56
+ "destructive"
57
+ ]).optional(),
58
+ type: e.enum([
59
+ "none",
60
+ "theme",
61
+ "solid",
62
+ "gradient",
63
+ "image"
64
+ ])
65
+ }), a = e.string().regex(/^[a-z][a-z0-9-]*$/), o = e.object({
66
+ block_type: e.union([n, a]),
67
+ content: e.record(e.string(), e.any()),
68
+ temp_id: e.string().optional()
69
+ }), s = e.object({
70
+ background: i,
71
+ column_blocks: e.array(e.array(o))
72
+ }), c = e.object({
73
+ autoplay: e.boolean().optional(),
74
+ background: i,
75
+ column_blocks: e.array(e.array(o)),
76
+ column_gap: e.enum([
77
+ "none",
78
+ "sm",
79
+ "md",
80
+ "lg",
81
+ "xl"
82
+ ]),
83
+ container_type: e.enum([
84
+ "full-width",
85
+ "container",
86
+ "container-sm",
87
+ "container-lg",
88
+ "container-xl"
89
+ ]),
90
+ is_hero: e.boolean().optional(),
91
+ padding: e.object({
92
+ bottom: e.enum([
93
+ "none",
94
+ "sm",
95
+ "md",
96
+ "lg",
97
+ "xl"
98
+ ]),
99
+ top: e.enum([
100
+ "none",
101
+ "sm",
102
+ "md",
103
+ "lg",
104
+ "xl"
105
+ ])
106
+ }),
107
+ responsive_columns: e.object({
108
+ desktop: e.union([
109
+ e.literal(1),
110
+ e.literal(2),
111
+ e.literal(3),
112
+ e.literal(4)
113
+ ]),
114
+ mobile: e.union([e.literal(1), e.literal(2)]),
115
+ tablet: e.union([
116
+ e.literal(1),
117
+ e.literal(2),
118
+ e.literal(3)
119
+ ])
120
+ }),
121
+ slider: e.boolean().optional(),
122
+ slides: e.array(s).optional(),
123
+ timeframe: e.number().optional(),
124
+ vertical_alignment: e.enum([
125
+ "start",
126
+ "center",
127
+ "end",
128
+ "stretch"
129
+ ]).optional()
130
+ }), l = {
131
+ button: e.object({
132
+ position: e.enum([
133
+ "left",
134
+ "center",
135
+ "right"
136
+ ]).optional(),
137
+ size: e.enum([
138
+ "default",
139
+ "sm",
140
+ "lg",
141
+ "full"
142
+ ]).optional(),
143
+ text: e.string(),
144
+ url: e.string(),
145
+ variant: e.enum([
146
+ "default",
147
+ "outline",
148
+ "secondary",
149
+ "ghost",
150
+ "link"
151
+ ]).optional()
152
+ }),
153
+ cart: e.object({}),
154
+ checkout: e.object({}),
155
+ featured_product: e.object({
156
+ imagePosition: e.enum(["left", "right"]).default("left"),
157
+ productId: e.string().min(1),
158
+ showBackground: e.boolean().default(!1)
159
+ }),
160
+ form: e.object({
161
+ fields: e.array(e.object({
162
+ field_type: e.enum([
163
+ "text",
164
+ "email",
165
+ "tel",
166
+ "url",
167
+ "number",
168
+ "textarea",
169
+ "select",
170
+ "radio",
171
+ "checkbox"
172
+ ]),
173
+ is_required: e.boolean(),
174
+ label: e.string(),
175
+ options: e.array(e.object({
176
+ label: e.string(),
177
+ value: e.string()
178
+ })).optional(),
179
+ placeholder: e.string().optional(),
180
+ temp_id: e.string()
181
+ })),
182
+ form_key: e.string().optional(),
183
+ recipient_email: e.string().email().optional(),
184
+ submit_button_text: e.string(),
185
+ success_message: e.string()
186
+ }),
187
+ heading: e.object({
188
+ level: e.union([
189
+ e.literal(1),
190
+ e.literal(2),
191
+ e.literal(3),
192
+ e.literal(4),
193
+ e.literal(5),
194
+ e.literal(6)
195
+ ]),
196
+ textAlign: e.enum([
197
+ "left",
198
+ "center",
199
+ "right",
200
+ "justify"
201
+ ]).optional(),
202
+ textColor: e.union([e.enum([
203
+ "foreground",
204
+ "primary",
205
+ "secondary",
206
+ "accent",
207
+ "muted",
208
+ "destructive",
209
+ "background"
210
+ ]), e.string().regex(/^(#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})|rgba?\([^)]+\)|hsla?\([^)]+\))$/i, "Must be a hex, rgb(a) or hsl(a) colour")]).optional().describe("Prefer a theme token so the heading adapts to dark mode; use a CSS colour only when the brand requires an exact value"),
211
+ text_content: e.string()
212
+ }),
213
+ image: e.object({
214
+ alt_text: e.string().optional(),
215
+ caption: e.string().optional(),
216
+ external_url: e.string().nullable().optional(),
217
+ height: e.number().nullable().optional(),
218
+ media_id: e.string().nullable().optional(),
219
+ object_key: e.string().nullable().optional(),
220
+ width: e.number().nullable().optional()
221
+ }),
222
+ posts_grid: e.object({
223
+ columns: e.number().min(1).max(6),
224
+ postsPerPage: e.number().min(1).max(50),
225
+ showPagination: e.boolean(),
226
+ title: e.string().optional()
227
+ }),
228
+ product_details: e.object({}),
229
+ product_grid: e.object({
230
+ categoryId: e.string().optional(),
231
+ categoryIds: e.array(e.string()).max(20).optional(),
232
+ limit: e.number().min(0).max(48).default(6),
233
+ productIds: e.array(e.string()).max(24).optional(),
234
+ showPagination: e.boolean().default(!1),
235
+ title: e.string().optional(),
236
+ type: e.enum([
237
+ "latest",
238
+ "category",
239
+ "manual"
240
+ ]).default("latest")
241
+ }),
242
+ section: c,
243
+ testimonial: e.object({
244
+ author_name: e.string().min(1),
245
+ author_title: e.string().optional(),
246
+ image_url: e.string().url().optional().or(e.literal("")),
247
+ quote: e.string().min(1)
248
+ }),
249
+ text: e.object({ html_content: e.string() }),
250
+ video_embed: e.object({
251
+ autoplay: e.boolean().optional(),
252
+ controls: e.boolean().optional(),
253
+ title: e.string().optional(),
254
+ url: e.string()
255
+ })
170
256
  };
171
- function v(o) {
172
- return d.includes(o);
257
+ function u(e) {
258
+ return t.includes(e);
173
259
  }
174
- function k(o) {
175
- return typeof o?.validateBlockContent == "function" ? o.validateBlockContent : null;
260
+ function d(e) {
261
+ return typeof e?.validateBlockContent == "function" ? e.validateBlockContent : null;
176
262
  }
177
- function B(o, n, r) {
178
- const l = k(r);
179
- if (l)
180
- return l(o, n);
181
- const i = _[o].safeParse(n);
182
- return i.success ? { errors: [], isValid: !0, warnings: [] } : {
183
- errors: i.error.issues.map((s) => {
184
- const e = s.path.join(".");
185
- return e ? `${e}: ${s.message}` : s.message;
186
- }),
187
- isValid: !1,
188
- warnings: []
189
- };
263
+ function f(e, t, n) {
264
+ let r = d(n);
265
+ if (r) return r(e, t);
266
+ let i = l[e].safeParse(t);
267
+ return i.success ? {
268
+ errors: [],
269
+ isValid: !0,
270
+ warnings: []
271
+ } : {
272
+ errors: i.error.issues.map((e) => {
273
+ let t = e.path.join(".");
274
+ return t ? `${t}: ${e.message}` : e.message;
275
+ }),
276
+ isValid: !1,
277
+ warnings: []
278
+ };
190
279
  }
191
- function j(o) {
192
- return Array.isArray(o.fields) ? o.fields.filter(
193
- (n) => !!n && typeof n == "object" && typeof n.key == "string" && typeof n.type == "string"
194
- ) : [];
280
+ function p(e) {
281
+ return Array.isArray(e.fields) ? e.fields.filter((e) => !!e && typeof e == "object" && typeof e.key == "string" && typeof e.type == "string") : [];
195
282
  }
196
- function x(o) {
197
- return o == null || typeof o == "string" && o.trim() === "" || Array.isArray(o) && o.length === 0;
283
+ function m(e) {
284
+ return e == null || typeof e == "string" && e.trim() === "" || Array.isArray(e) && e.length === 0;
198
285
  }
199
- function S(o, n) {
200
- if (!n || typeof n != "object" || Array.isArray(n))
201
- return {
202
- errors: ["content must be a JSON object of { field_key: value } pairs."],
203
- isValid: !1,
204
- warnings: []
205
- };
206
- const r = j(o), l = new Set(r.map((e) => e.key)), i = [], s = [];
207
- for (const e of Object.keys(n))
208
- l.has(e) || i.push(
209
- `Unknown field "${e}" for custom block "${o.slug}". Known fields: ${[...l].join(", ") || "(none)"}.`
210
- );
211
- for (const e of r) {
212
- const a = n[e.key];
213
- if (x(a)) {
214
- e.required && i.push(`Field "${e.key}" is required.`);
215
- continue;
216
- }
217
- if (e.type === "text" || e.type === "rich-text") {
218
- if (typeof a != "string") {
219
- i.push(`Field "${e.key}" must be a string${e.type === "rich-text" ? " of HTML" : ""}.`);
220
- continue;
221
- }
222
- typeof e.max_length == "number" && a.length > e.max_length && i.push(`Field "${e.key}" exceeds its ${e.max_length}-character limit.`), typeof e.min_length == "number" && a.length < e.min_length && i.push(`Field "${e.key}" is shorter than its ${e.min_length}-character minimum.`);
223
- continue;
224
- }
225
- if (e.type === "image_r2") {
226
- const c = a;
227
- (typeof a != "object" || Array.isArray(a) || typeof c.object_key != "string" || typeof c.url != "string") && i.push(
228
- `Field "${e.key}" must be an uploaded image object with object_key and url (upload it with upload_media first) or null.`
229
- );
230
- continue;
231
- }
232
- if (e.type === "db_relation") {
233
- const c = (u) => typeof u == "string" || typeof u == "number";
234
- e.multiple ? (!Array.isArray(a) || !a.every(c)) && i.push(`Field "${e.key}" must be an array of related record ids.`) : c(a) || i.push(`Field "${e.key}" must be a single related record id.`);
235
- continue;
236
- }
237
- s.push(`Field "${e.key}" has an unrecognised type "${String(e.type)}"; it was not validated.`);
238
- }
239
- return { errors: i, isValid: i.length === 0, warnings: s };
286
+ function h(e, t) {
287
+ if (!t || typeof t != "object" || Array.isArray(t)) return {
288
+ errors: ["content must be a JSON object of { field_key: value } pairs."],
289
+ isValid: !1,
290
+ warnings: []
291
+ };
292
+ let n = p(e), r = new Set(n.map((e) => e.key)), i = [], a = [];
293
+ for (let n of Object.keys(t)) r.has(n) || i.push(`Unknown field "${n}" for custom block "${e.slug}". Known fields: ${[...r].join(", ") || "(none)"}.`);
294
+ for (let e of n) {
295
+ let n = t[e.key];
296
+ if (m(n)) {
297
+ e.required && i.push(`Field "${e.key}" is required.`);
298
+ continue;
299
+ }
300
+ if (e.type === "text" || e.type === "rich-text") {
301
+ if (typeof n != "string") {
302
+ i.push(`Field "${e.key}" must be a string${e.type === "rich-text" ? " of HTML" : ""}.`);
303
+ continue;
304
+ }
305
+ typeof e.max_length == "number" && n.length > e.max_length && i.push(`Field "${e.key}" exceeds its ${e.max_length}-character limit.`), typeof e.min_length == "number" && n.length < e.min_length && i.push(`Field "${e.key}" is shorter than its ${e.min_length}-character minimum.`);
306
+ continue;
307
+ }
308
+ if (e.type === "image_r2") {
309
+ let t = n;
310
+ (typeof n != "object" || Array.isArray(n) || typeof t.object_key != "string" || typeof t.url != "string") && i.push(`Field "${e.key}" must be an uploaded image object with object_key and url (upload it with upload_media first) or null.`);
311
+ continue;
312
+ }
313
+ if (e.type === "db_relation") {
314
+ let t = (e) => typeof e == "string" || typeof e == "number";
315
+ e.multiple ? (!Array.isArray(n) || !n.every(t)) && i.push(`Field "${e.key}" must be an array of related record ids.`) : t(n) || i.push(`Field "${e.key}" must be a single related record id.`);
316
+ continue;
317
+ }
318
+ a.push(`Field "${e.key}" has an unrecognised type "${String(e.type)}"; it was not validated.`);
319
+ }
320
+ return {
321
+ errors: i,
322
+ isValid: i.length === 0,
323
+ warnings: a
324
+ };
240
325
  }
241
- async function A(o) {
242
- const { data: n, error: r } = await o.from("custom_block_definitions").select("slug, name, fields");
243
- if (r)
244
- throw new Error(
245
- `Could not read the custom block definitions: ${typeof r == "object" && r && "message" in r ? String(r.message) : String(r)}`
246
- );
247
- return (Array.isArray(n) ? n : []).filter(
248
- (l) => !!l && typeof l.slug == "string"
249
- );
326
+ async function g(e) {
327
+ let { data: t, error: n } = await e.from("custom_block_definitions").select("slug, name, fields");
328
+ if (n) throw Error(`Could not read the custom block definitions: ${typeof n == "object" && n && "message" in n ? String(n.message) : String(n)}`);
329
+ return (Array.isArray(t) ? t : []).filter((e) => !!e && typeof e.slug == "string");
250
330
  }
251
- export {
252
- d as availableCortexAiBlockTypes,
253
- b as cortexAiBlockTypeSchema,
254
- f as customBlockSlugPatternSchema,
255
- _ as fallbackBlockSchemas,
256
- v as isValidBlockType,
257
- A as loadCustomBlockDefinitions,
258
- j as readCustomBlockFields,
259
- h as sectionBlockFallbackSchema,
260
- B as validateCortexBlockContent,
261
- S as validateCustomBlockInstanceContent
262
- };
331
+ //#endregion
332
+ export { t as availableCortexAiBlockTypes, n as cortexAiBlockTypeSchema, a as customBlockSlugPatternSchema, l as fallbackBlockSchemas, u as isValidBlockType, g as loadCustomBlockDefinitions, p as readCustomBlockFields, c as sectionBlockFallbackSchema, f as validateCortexBlockContent, h as validateCustomBlockInstanceContent };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("@nextblock-cms/utils/custom-blocks"),a="id, slug, name, description, fields, layout_schema, is_original";class c extends Error{code;status;constructor(e,i){super(e),this.name="CortexWidgetRegistryInsertError",this.code=i?.code,this.status=i?.status??500}}function s(t){return JSON.parse(JSON.stringify(t))}function d(t){return t==="23505"?409:t==="42501"?403:500}function u(t){const e=n.customBlockDefinitionCreateSchema.parse({...t,is_original:!0});return{description:e.description,fields:s(e.fields),is_original:!0,layout_schema:s(e.layout_schema),name:e.name,slug:e.slug}}async function l(t,e){const i=u(e),{data:o,error:r}=await t.from("custom_block_definitions").insert(i).select(a).single();if(r||!o)throw new c(r?.message??"Failed to insert Cortex custom block definition.",{code:r?.code,status:d(r?.code)});return n.customBlockDefinitionRowSchema.parse(o)}exports.CORTEX_WIDGET_DEFINITION_SELECT=a;exports.CortexWidgetRegistryInsertError=c;exports.buildCortexWidgetDefinitionInsertPayload=u;exports.insertCortexWidgetDefinition=l;
1
+ let e=require("@nextblock-cms/utils/custom-blocks");var t=`id, slug, name, description, fields, layout_schema, is_original`,n=class extends Error{code;status;constructor(e,t){super(e),this.name=`CortexWidgetRegistryInsertError`,this.code=t?.code,this.status=t?.status??500}};function r(e){return JSON.parse(JSON.stringify(e))}function i(e){return e===`23505`?409:e===`42501`?403:500}function a(t){let n=e.customBlockDefinitionCreateSchema.parse({...t,is_original:!0});return{description:n.description,fields:r(n.fields),is_original:!0,layout_schema:r(n.layout_schema),name:n.name,slug:n.slug}}async function o(r,o){let s=a(o),{data:c,error:l}=await r.from(`custom_block_definitions`).insert(s).select(t).single();if(l||!c)throw new n(l?.message??`Failed to insert Cortex custom block definition.`,{code:l?.code,status:i(l?.code)});return e.customBlockDefinitionRowSchema.parse(c)}exports.CORTEX_WIDGET_DEFINITION_SELECT=t,exports.CortexWidgetRegistryInsertError=n,exports.buildCortexWidgetDefinitionInsertPayload=a,exports.insertCortexWidgetDefinition=o;