@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,227 +1,173 @@
1
- import { generateText as _ } from "ai";
2
- import { runWithCortexAiModelFallback as w, omitUnsupportedCortexAiModelOptions as I, getHttpStatusCode as y, isOpenRouterRecoverableRoutingError as R } from "./ai-model-registry.es.js";
3
- import { truncateOnWordBoundary as C } from "./ai-seo-metadata.es.js";
4
- const S = "Cortex AI vision generation can only be imported from server-side code.";
5
- function L() {
6
- if (!(typeof window > "u"))
7
- throw new Error(S);
1
+ import { getHttpStatusCode as e, isOpenRouterRecoverableRoutingError as t, omitUnsupportedCortexAiModelOptions as n, runWithCortexAiModelFallback as r } from "./ai-model-registry.es.js";
2
+ import { truncateOnWordBoundary as i } from "./ai-seo-metadata.es.js";
3
+ import { generateText as a } from "ai";
4
+ //#region libs/cortex/src/lib/ai-vision.ts
5
+ var o = "Cortex AI vision generation can only be imported from server-side code.";
6
+ function s() {
7
+ if (typeof window < "u") throw Error(o);
8
8
  }
9
- const p = [
10
- "google/gemma-4-31b-it:free",
11
- "google/gemma-4-26b-a4b-it:free",
12
- "google/gemini-2.5-flash-lite",
13
- "qwen/qwen3-vl-32b-instruct",
14
- "openai/gpt-4o-mini",
15
- "google/gemini-2.5-flash"
16
- ], O = [
17
- // Dedicated vision-language builds: "qwen3-vl-32b-instruct", "internvl3-78b".
18
- /(?:^|\/)[^/]*-vl(?:[-:]|$)/i,
19
- // Explicitly named vision variants: "llama-3.2-11b-vision-instruct".
20
- /vision/i,
21
- // Whole families that are multimodal end to end.
22
- /(?:^|\/)gemini-/i,
23
- /(?:^|\/)gemma-[3-9]/i,
24
- /(?:^|\/)gpt-(?:4o|4\.1|5)/i,
25
- /(?:^|\/)claude-/i,
26
- /(?:^|\/)llama-4/i,
27
- /(?:^|\/)pixtral/i,
28
- /(?:^|\/)mistral-(?:small|medium|large)-3/i,
29
- /(?:^|\/)nova-(?:lite|pro|premier)/i
30
- ], f = 125, m = { max: 1e3, min: 20 }, M = 6e4, g = /* @__PURE__ */ new Set([
31
- '"',
32
- "'",
33
- "«",
34
- // «
35
- "»",
36
- // »
37
- "‘",
38
- // ‘
39
- "’",
40
- // ’
41
- "‚",
42
- // ‚
43
- "“",
44
- // “
45
- "”",
46
- // ”
47
- "„",
48
- // „
49
- "`"
50
- ]), v = /^(?:here(?:'s|’s| is)\s+)?(?:the\s+)?alt(?:[-\s]?text)?\s*[:–—-]\s*/i, N = /^(?:this\s+is\s+)?(?:an?|the)?\s*(?:image|photo|photograph|picture|pic|graphic|illustration|rendering|render)\s+(?:of|showing|depicting|that\s+shows)\s+/i;
51
- function U(e) {
52
- const o = /* @__PURE__ */ new Set(), t = [];
53
- for (const n of e) {
54
- const r = n?.trim();
55
- !r || o.has(r) || (o.add(r), t.push(r));
56
- }
57
- return t;
9
+ var c = [
10
+ "google/gemma-4-31b-it:free",
11
+ "google/gemma-4-26b-a4b-it:free",
12
+ "google/gemini-2.5-flash-lite",
13
+ "qwen/qwen3-vl-32b-instruct",
14
+ "openai/gpt-4o-mini",
15
+ "google/gemini-2.5-flash"
16
+ ], l = [
17
+ /(?:^|\/)[^/]*-vl(?:[-:]|$)/i,
18
+ /vision/i,
19
+ /(?:^|\/)gemini-/i,
20
+ /(?:^|\/)gemma-[3-9]/i,
21
+ /(?:^|\/)gpt-(?:4o|4\.1|5)/i,
22
+ /(?:^|\/)claude-/i,
23
+ /(?:^|\/)llama-4/i,
24
+ /(?:^|\/)pixtral/i,
25
+ /(?:^|\/)mistral-(?:small|medium|large)-3/i,
26
+ /(?:^|\/)nova-(?:lite|pro|premier)/i
27
+ ], u = 125, d = {
28
+ max: 1e3,
29
+ min: 20
30
+ }, f = 6e4, p = /* @__PURE__ */ new Set([
31
+ "\"",
32
+ "'",
33
+ "«",
34
+ "»",
35
+ "‘",
36
+ "’",
37
+ "‚",
38
+ "“",
39
+ "”",
40
+ "„",
41
+ "`"
42
+ ]), m = /^(?:here(?:'s|’s| is)\s+)?(?:the\s+)?alt(?:[-\s]?text)?\s*[:–—-]\s*/i, h = /^(?:this\s+is\s+)?(?:an?|the)?\s*(?:image|photo|photograph|picture|pic|graphic|illustration|rendering|render)\s+(?:of|showing|depicting|that\s+shows)\s+/i;
43
+ function g(e) {
44
+ let t = /* @__PURE__ */ new Set(), n = [];
45
+ for (let r of e) {
46
+ let e = r?.trim();
47
+ e && !t.has(e) && (t.add(e), n.push(e));
48
+ }
49
+ return n;
58
50
  }
59
- function X(e) {
60
- const o = e?.trim();
61
- return o ? p.includes(o) ? !0 : O.some((t) => t.test(o)) : !1;
51
+ function _(e) {
52
+ let t = e?.trim();
53
+ return t ? c.includes(t) ? !0 : l.some((e) => e.test(t)) : !1;
62
54
  }
63
- function P(e) {
64
- const o = e.requestedModelId?.trim() || null, t = e.selectedModel?.modelId?.trim() || null, n = e.credentialSource !== "env" && t && X(t) ? t : null;
65
- return {
66
- modelIds: U([
67
- o,
68
- n,
69
- ...p
70
- ])
71
- };
55
+ function v(e) {
56
+ let t = e.requestedModelId?.trim() || null, n = e.selectedModel?.modelId?.trim() || null;
57
+ return { modelIds: g([
58
+ t,
59
+ e.credentialSource !== "env" && n && _(n) ? n : null,
60
+ ...c
61
+ ]) };
72
62
  }
73
- function h(e) {
74
- let o = e.trim();
75
- for (; o.length >= 2 && g.has(o[0]) && g.has(o[o.length - 1]); )
76
- o = o.slice(1, -1).trim();
77
- return o;
63
+ function y(e) {
64
+ let t = e.trim();
65
+ for (; t.length >= 2 && p.has(t[0]) && p.has(t[t.length - 1]);) t = t.slice(1, -1).trim();
66
+ return t;
78
67
  }
79
- function q(e) {
80
- return !e.endsWith(".") || e.endsWith("...") || e.endsWith("…") ? e : (e.match(/[.!?](?=\s|$)/g) || []).length === 1 ? e.slice(0, -1).trimEnd() : e;
68
+ function b(e) {
69
+ return !e.endsWith(".") || e.endsWith("...") || e.endsWith("…") ? e : (e.match(/[.!?](?=\s|$)/g) || []).length === 1 ? e.slice(0, -1).trimEnd() : e;
81
70
  }
82
- function D(e, o = f) {
83
- let t = e.replace(/\s+/g, " ").trim(), n = !1;
84
- for (let r = 0; r < 2; r++) {
85
- t = h(t);
86
- const a = t.replace(v, "");
87
- a !== t && (t = a.trim(), n = !0), t = h(t);
88
- const i = t.replace(N, "");
89
- i !== t && (t = i.trim(), n = !0);
90
- }
91
- return n && t && (t = t.charAt(0).toUpperCase() + t.slice(1)), C(q(t), o);
71
+ function x(e, t = 125) {
72
+ let n = e.replace(/\s+/g, " ").trim(), r = !1;
73
+ for (let e = 0; e < 2; e++) {
74
+ n = y(n);
75
+ let e = n.replace(m, "");
76
+ e !== n && (n = e.trim(), r = !0), n = y(n);
77
+ let t = n.replace(h, "");
78
+ t !== n && (n = t.trim(), r = !0);
79
+ }
80
+ return r && n && (n = n.charAt(0).toUpperCase() + n.slice(1)), i(b(n), t);
92
81
  }
93
- function k(e) {
94
- const o = e.trim();
95
- if (!o)
96
- throw new Error("Cortex AI alt text generation requires an image URL.");
97
- let t;
98
- try {
99
- t = new URL(o);
100
- } catch {
101
- throw new Error(
102
- `Cortex AI alt text generation requires an absolute http(s) image URL, received "${o}". A storage key or site-relative path must be resolved to a publicly fetchable URL first, because the model provider downloads the image server-side.`
103
- );
104
- }
105
- if (t.protocol !== "http:" && t.protocol !== "https:")
106
- throw new Error(
107
- `Cortex AI alt text generation requires an http(s) image URL, received the "${t.protocol}" scheme.`
108
- );
109
- return t;
82
+ function S(e) {
83
+ let t = e.trim();
84
+ if (!t) throw Error("Cortex AI alt text generation requires an image URL.");
85
+ let n;
86
+ try {
87
+ n = new URL(t);
88
+ } catch {
89
+ throw Error(`Cortex AI alt text generation requires an absolute http(s) image URL, received "${t}". A storage key or site-relative path must be resolved to a publicly fetchable URL first, because the model provider downloads the image server-side.`);
90
+ }
91
+ if (n.protocol !== "http:" && n.protocol !== "https:") throw Error(`Cortex AI alt text generation requires an http(s) image URL, received the "${n.protocol}" scheme.`);
92
+ return n;
110
93
  }
111
- function B(e) {
112
- return [
113
- "You are NextBlock Cortex AI, writing the alt attribute for an image on a website.",
114
- "You are writing for a person using a screen reader who cannot see the image at all.",
115
- "Describe only what is visibly present in the image: subjects, their appearance, what they are doing, the setting, and any text that appears in the image.",
116
- "Never state or guess anything you cannot see — no names, no locations, no dates, no brands, no emotions, and no backstory unless they are legible in the image itself.",
117
- `Write one short factual description of at most ${e} characters.`,
118
- 'Do not begin with "image of", "photo of", "picture of", "graphic of", or any similar phrase; the screen reader already announces that this is an image.',
119
- 'Do not add a label such as "Alt text:" and do not wrap the description in quotation marks.',
120
- "Do not keyword-stuff, do not list search terms, and do not repeat a word for emphasis.",
121
- "Return plain text only: one line, no markdown, no HTML, no JSON, no commentary, no alternatives to choose between.",
122
- "If surrounding page context is supplied, use it ONLY to disambiguate what you can already see — for example to choose the right word for an object or to know which product is pictured. Never use it to add detail that is not visible in the image."
123
- ].join(" ");
94
+ function C(e) {
95
+ return [
96
+ "You are NextBlock Cortex AI, writing the alt attribute for an image on a website.",
97
+ "You are writing for a person using a screen reader who cannot see the image at all.",
98
+ "Describe only what is visibly present in the image: subjects, their appearance, what they are doing, the setting, and any text that appears in the image.",
99
+ "Never state or guess anything you cannot see — no names, no locations, no dates, no brands, no emotions, and no backstory unless they are legible in the image itself.",
100
+ `Write one short factual description of at most ${e} characters.`,
101
+ "Do not begin with \"image of\", \"photo of\", \"picture of\", \"graphic of\", or any similar phrase; the screen reader already announces that this is an image.",
102
+ "Do not add a label such as \"Alt text:\" and do not wrap the description in quotation marks.",
103
+ "Do not keyword-stuff, do not list search terms, and do not repeat a word for emphasis.",
104
+ "Return plain text only: one line, no markdown, no HTML, no JSON, no commentary, no alternatives to choose between.",
105
+ "If surrounding page context is supplied, use it ONLY to disambiguate what you can already see — for example to choose the right word for an object or to know which product is pictured. Never use it to add detail that is not visible in the image."
106
+ ].join(" ");
124
107
  }
125
- function F(e) {
126
- return [
127
- `Write the alt attribute for this image, at most ${e.maxLength} characters.`,
128
- e.context ? `Surrounding page context, for disambiguation only: ${e.context}` : null
129
- ].filter(Boolean).join(`
130
-
131
- `);
108
+ function w(e) {
109
+ return [`Write the alt attribute for this image, at most ${e.maxLength} characters.`, e.context ? `Surrounding page context, for disambiguation only: ${e.context}` : null].filter(Boolean).join("\n\n");
132
110
  }
133
- function V(e) {
134
- const o = y(e);
135
- if (o === 401 || o === 402 || o === 403)
136
- return !1;
137
- if (R(e) || o && o >= 500)
138
- return !0;
139
- const t = e instanceof Error ? e.message : String(e);
140
- return /NoContentGenerated|No content generated|Provider returned error|empty alt text|image|modality|multimodal|not support|unsupported|aborted|abort|timeout|timed out/i.test(
141
- t
142
- );
111
+ function T(n) {
112
+ let r = e(n);
113
+ if (r === 401 || r === 402 || r === 403) return !1;
114
+ if (t(n) || r && r >= 500) return !0;
115
+ let i = n instanceof Error ? n.message : String(n);
116
+ return /NoContentGenerated|No content generated|Provider returned error|empty alt text|image|modality|multimodal|not support|unsupported|aborted|abort|timeout|timed out/i.test(i);
143
117
  }
144
- async function H(e) {
145
- L();
146
- const o = k(e.imageUrl), t = Number.isFinite(e.maxLength) ? Math.round(e.maxLength) : f, n = Math.min(
147
- m.max,
148
- Math.max(m.min, t)
149
- ), r = e.context?.replace(/\s+/g, " ").trim() || null, { createCortexAiOpenRouterClient: a } = await import("./ai-client.es.js"), i = await a({
150
- apiKey: e.apiKey || void 0
151
- }), T = P({
152
- credentialSource: i.credentialSource,
153
- requestedModelId: e.modelId,
154
- selectedModel: i.modelSelection
155
- }), b = [
156
- {
157
- content: [
158
- {
159
- text: F({ context: r, maxLength: n }),
160
- type: "text"
161
- },
162
- {
163
- // `mediaType` is intentionally omitted. The SDK downloads the image and
164
- // derives the media type from the response, whereas guessing it from the
165
- // URL is unreliable for the CDN and signed-URL shapes this CMS produces —
166
- // query strings, no extension, or an extension that disagrees with what
167
- // the storage bucket actually serves. A wrong media type is worse than a
168
- // missing one, because the provider will reject the part outright.
169
- image: o,
170
- type: "image"
171
- }
172
- ],
173
- role: "user"
174
- }
175
- ], l = await w({
176
- modelIds: T.modelIds,
177
- shouldRetry: V,
178
- execute: async (c) => {
179
- const s = new AbortController(), x = setTimeout(
180
- () => s.abort(),
181
- M
182
- ), d = () => s.abort();
183
- e.abortSignal?.addEventListener("abort", d, { once: !0 }), e.abortSignal?.aborted && s.abort();
184
- try {
185
- const A = I(
186
- {
187
- abortSignal: s.signal,
188
- // Alt text is one short line, but several models in the chain emit
189
- // reasoning tokens against the same budget, so leave headroom rather
190
- // than truncating the answer to nothing on those.
191
- maxOutputTokens: 400,
192
- maxRetries: 0,
193
- messages: b,
194
- system: B(n),
195
- temperature: 0.2
196
- },
197
- {
198
- modelId: c,
199
- modelSelection: i.modelSelection
200
- }
201
- ), E = await _({
202
- ...A,
203
- model: i.model(c)
204
- }), u = D(E.text, n);
205
- if (!u)
206
- throw new Error("Cortex AI returned empty alt text.");
207
- return u;
208
- } finally {
209
- clearTimeout(x), e.abortSignal?.removeEventListener("abort", d);
210
- }
211
- }
212
- });
213
- return {
214
- altText: l.result,
215
- attempts: l.attempts.length,
216
- credentialSource: i.credentialSource,
217
- modelId: l.modelId
218
- };
118
+ async function E(e) {
119
+ s();
120
+ let t = S(e.imageUrl), i = Number.isFinite(e.maxLength) ? Math.round(e.maxLength) : 125, o = Math.min(d.max, Math.max(d.min, i)), c = e.context?.replace(/\s+/g, " ").trim() || null, { createCortexAiOpenRouterClient: l } = await import("./ai-client.es.js"), u = await l({ apiKey: e.apiKey || void 0 }), p = v({
121
+ credentialSource: u.credentialSource,
122
+ requestedModelId: e.modelId,
123
+ selectedModel: u.modelSelection
124
+ }), { downloadCortexVisionImage: m } = await import("./vision-image-download.es.js"), h = await m(t, { abortSignal: e.abortSignal }), g = [{
125
+ content: [{
126
+ text: w({
127
+ context: c,
128
+ maxLength: o
129
+ }),
130
+ type: "text"
131
+ }, {
132
+ data: h.data,
133
+ mediaType: h.mediaType,
134
+ type: "file"
135
+ }],
136
+ role: "user"
137
+ }], _ = await r({
138
+ modelIds: p.modelIds,
139
+ shouldRetry: T,
140
+ execute: async (t) => {
141
+ let r = new AbortController(), i = setTimeout(() => r.abort(), f), s = () => r.abort();
142
+ e.abortSignal?.addEventListener("abort", s, { once: !0 }), e.abortSignal?.aborted && r.abort();
143
+ try {
144
+ let e = n({
145
+ abortSignal: r.signal,
146
+ maxOutputTokens: 400,
147
+ maxRetries: 0,
148
+ messages: g,
149
+ instructions: C(o),
150
+ temperature: .2
151
+ }, {
152
+ modelId: t,
153
+ modelSelection: u.modelSelection
154
+ }), i = x((await a({
155
+ ...e,
156
+ model: u.model(t)
157
+ })).text, o);
158
+ if (!i) throw Error("Cortex AI returned empty alt text.");
159
+ return i;
160
+ } finally {
161
+ clearTimeout(i), e.abortSignal?.removeEventListener("abort", s);
162
+ }
163
+ }
164
+ });
165
+ return {
166
+ altText: _.result,
167
+ attempts: _.attempts.length,
168
+ credentialSource: u.credentialSource,
169
+ modelId: _.modelId
170
+ };
219
171
  }
220
- export {
221
- f as CORTEX_AI_DEFAULT_ALT_TEXT_MAX_LENGTH,
222
- p as CORTEX_AI_VISION_MODEL_FALLBACK_REGISTRY,
223
- P as buildCortexAiVisionRoutingPolicy,
224
- H as generateCortexAiAltText,
225
- X as isKnownVisionCapableCortexAiModelId,
226
- D as normalizeGeneratedAltText
227
- };
172
+ //#endregion
173
+ export { u as CORTEX_AI_DEFAULT_ALT_TEXT_MAX_LENGTH, c as CORTEX_AI_VISION_MODEL_FALLBACK_REGISTRY, v as buildCortexAiVisionRoutingPolicy, E as generateCortexAiAltText, _ as isKnownVisionCapableCortexAiModelId, x as normalizeGeneratedAltText };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});require("./zod-config.cjs.js");const t=require("zod"),u=["text","heading","image","button","posts_grid","video_embed","section","form","testimonial","product_grid","featured_product","cart","checkout","product_details"],z=t.z.enum(u),d=t.z.object({direction:t.z.string().optional(),stops:t.z.array(t.z.object({color:t.z.string(),position:t.z.number()})),type:t.z.enum(["linear","radial"])}),g=t.z.object({gradient:d.optional(),image:t.z.object({alt_text:t.z.string().optional(),blur_data_url:t.z.string().optional(),external_url:t.z.string().optional(),height:t.z.number().optional(),media_id:t.z.string().optional(),object_key:t.z.string().optional(),overlay:t.z.object({gradient:d,type:t.z.literal("gradient")}).optional(),position:t.z.enum(["center","top","bottom","left","right"]),quality:t.z.number().nullable().optional(),size:t.z.enum(["cover","contain"]),width:t.z.number().optional()}).optional(),min_height:t.z.string().optional(),solid_color:t.z.string().optional(),theme:t.z.enum(["primary","secondary","muted","accent","destructive"]).optional(),type:t.z.enum(["none","theme","solid","gradient","image"])}),p=t.z.string().regex(/^[a-z][a-z0-9-]*$/),b=t.z.object({block_type:t.z.union([z,p]),content:t.z.record(t.z.string(),t.z.any()),temp_id:t.z.string().optional()}),k=t.z.object({background:g,column_blocks:t.z.array(t.z.array(b))}),y=t.z.object({autoplay:t.z.boolean().optional(),background:g,column_blocks:t.z.array(t.z.array(b)),column_gap:t.z.enum(["none","sm","md","lg","xl"]),container_type:t.z.enum(["full-width","container","container-sm","container-lg","container-xl"]),is_hero:t.z.boolean().optional(),padding:t.z.object({bottom:t.z.enum(["none","sm","md","lg","xl"]),top:t.z.enum(["none","sm","md","lg","xl"])}),responsive_columns:t.z.object({desktop:t.z.union([t.z.literal(1),t.z.literal(2),t.z.literal(3),t.z.literal(4)]),mobile:t.z.union([t.z.literal(1),t.z.literal(2)]),tablet:t.z.union([t.z.literal(1),t.z.literal(2),t.z.literal(3)])}),slider:t.z.boolean().optional(),slides:t.z.array(k).optional(),timeframe:t.z.number().optional(),vertical_alignment:t.z.enum(["start","center","end","stretch"]).optional()}),f={button:t.z.object({position:t.z.enum(["left","center","right"]).optional(),size:t.z.enum(["default","sm","lg","full"]).optional(),text:t.z.string(),url:t.z.string(),variant:t.z.enum(["default","outline","secondary","ghost","link"]).optional()}),cart:t.z.object({}),checkout:t.z.object({}),featured_product:t.z.object({imagePosition:t.z.enum(["left","right"]).default("left"),productId:t.z.string().min(1),showBackground:t.z.boolean().default(!1)}),form:t.z.object({fields:t.z.array(t.z.object({field_type:t.z.enum(["text","email","tel","url","number","textarea","select","radio","checkbox"]),is_required:t.z.boolean(),label:t.z.string(),options:t.z.array(t.z.object({label:t.z.string(),value:t.z.string()})).optional(),placeholder:t.z.string().optional(),temp_id:t.z.string()})),form_key:t.z.string().optional(),recipient_email:t.z.string().email().optional(),submit_button_text:t.z.string(),success_message:t.z.string()}),heading:t.z.object({level:t.z.union([t.z.literal(1),t.z.literal(2),t.z.literal(3),t.z.literal(4),t.z.literal(5),t.z.literal(6)]),textAlign:t.z.enum(["left","center","right","justify"]).optional(),textColor:t.z.union([t.z.enum(["foreground","primary","secondary","accent","muted","destructive","background"]),t.z.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"),text_content:t.z.string()}),image:t.z.object({alt_text:t.z.string().optional(),caption:t.z.string().optional(),external_url:t.z.string().nullable().optional(),height:t.z.number().nullable().optional(),media_id:t.z.string().nullable().optional(),object_key:t.z.string().nullable().optional(),width:t.z.number().nullable().optional()}),posts_grid:t.z.object({columns:t.z.number().min(1).max(6),postsPerPage:t.z.number().min(1).max(50),showPagination:t.z.boolean(),title:t.z.string().optional()}),product_details:t.z.object({}),product_grid:t.z.object({categoryId:t.z.string().optional(),categoryIds:t.z.array(t.z.string()).max(20).optional(),limit:t.z.number().min(0).max(48).default(6),productIds:t.z.array(t.z.string()).max(24).optional(),showPagination:t.z.boolean().default(!1),title:t.z.string().optional(),type:t.z.enum(["latest","category","manual"]).default("latest")}),section:y,testimonial:t.z.object({author_name:t.z.string().min(1),author_title:t.z.string().optional(),image_url:t.z.string().url().optional().or(t.z.literal("")),quote:t.z.string().min(1)}),text:t.z.object({html_content:t.z.string()}),video_embed:t.z.object({autoplay:t.z.boolean().optional(),controls:t.z.boolean().optional(),title:t.z.string().optional(),url:t.z.string()})};function _(o){return u.includes(o)}function j(o){return typeof o?.validateBlockContent=="function"?o.validateBlockContent:null}function x(o,n,a){const l=j(a);if(l)return l(o,n);const i=f[o].safeParse(n);return i.success?{errors:[],isValid:!0,warnings:[]}:{errors:i.error.issues.map(s=>{const e=s.path.join(".");return e?`${e}: ${s.message}`:s.message}),isValid:!1,warnings:[]}}function h(o){return Array.isArray(o.fields)?o.fields.filter(n=>!!n&&typeof n=="object"&&typeof n.key=="string"&&typeof n.type=="string"):[]}function B(o){return o==null||typeof o=="string"&&o.trim()===""||Array.isArray(o)&&o.length===0}function S(o,n){if(!n||typeof n!="object"||Array.isArray(n))return{errors:["content must be a JSON object of { field_key: value } pairs."],isValid:!1,warnings:[]};const a=h(o),l=new Set(a.map(e=>e.key)),i=[],s=[];for(const e of Object.keys(n))l.has(e)||i.push(`Unknown field "${e}" for custom block "${o.slug}". Known fields: ${[...l].join(", ")||"(none)"}.`);for(const e of a){const r=n[e.key];if(B(r)){e.required&&i.push(`Field "${e.key}" is required.`);continue}if(e.type==="text"||e.type==="rich-text"){if(typeof r!="string"){i.push(`Field "${e.key}" must be a string${e.type==="rich-text"?" of HTML":""}.`);continue}typeof e.max_length=="number"&&r.length>e.max_length&&i.push(`Field "${e.key}" exceeds its ${e.max_length}-character limit.`),typeof e.min_length=="number"&&r.length<e.min_length&&i.push(`Field "${e.key}" is shorter than its ${e.min_length}-character minimum.`);continue}if(e.type==="image_r2"){const c=r;(typeof r!="object"||Array.isArray(r)||typeof c.object_key!="string"||typeof c.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.`);continue}if(e.type==="db_relation"){const c=m=>typeof m=="string"||typeof m=="number";e.multiple?(!Array.isArray(r)||!r.every(c))&&i.push(`Field "${e.key}" must be an array of related record ids.`):c(r)||i.push(`Field "${e.key}" must be a single related record id.`);continue}s.push(`Field "${e.key}" has an unrecognised type "${String(e.type)}"; it was not validated.`)}return{errors:i,isValid:i.length===0,warnings:s}}async function C(o){const{data:n,error:a}=await o.from("custom_block_definitions").select("slug, name, fields");if(a)throw new Error(`Could not read the custom block definitions: ${typeof a=="object"&&a&&"message"in a?String(a.message):String(a)}`);return(Array.isArray(n)?n:[]).filter(l=>!!l&&typeof l.slug=="string")}exports.availableCortexAiBlockTypes=u;exports.cortexAiBlockTypeSchema=z;exports.customBlockSlugPatternSchema=p;exports.fallbackBlockSchemas=f;exports.isValidBlockType=_;exports.loadCustomBlockDefinitions=C;exports.readCustomBlockFields=h;exports.sectionBlockFallbackSchema=y;exports.validateCortexBlockContent=x;exports.validateCustomBlockInstanceContent=S;
1
+ require("./zod-config.cjs.js");let e=require("zod");var t=[`text`,`heading`,`image`,`button`,`posts_grid`,`video_embed`,`section`,`form`,`testimonial`,`product_grid`,`featured_product`,`cart`,`checkout`,`product_details`],n=e.z.enum(t),r=e.z.object({direction:e.z.string().optional(),stops:e.z.array(e.z.object({color:e.z.string(),position:e.z.number()})),type:e.z.enum([`linear`,`radial`])}),i=e.z.object({gradient:r.optional(),image:e.z.object({alt_text:e.z.string().optional(),blur_data_url:e.z.string().optional(),external_url:e.z.string().optional(),height:e.z.number().optional(),media_id:e.z.string().optional(),object_key:e.z.string().optional(),overlay:e.z.object({gradient:r,type:e.z.literal(`gradient`)}).optional(),position:e.z.enum([`center`,`top`,`bottom`,`left`,`right`]),quality:e.z.number().nullable().optional(),size:e.z.enum([`cover`,`contain`]),width:e.z.number().optional()}).optional(),min_height:e.z.string().optional(),solid_color:e.z.string().optional(),theme:e.z.enum([`primary`,`secondary`,`muted`,`accent`,`destructive`]).optional(),type:e.z.enum([`none`,`theme`,`solid`,`gradient`,`image`])}),a=e.z.string().regex(/^[a-z][a-z0-9-]*$/),o=e.z.object({block_type:e.z.union([n,a]),content:e.z.record(e.z.string(),e.z.any()),temp_id:e.z.string().optional()}),s=e.z.object({background:i,column_blocks:e.z.array(e.z.array(o))}),c=e.z.object({autoplay:e.z.boolean().optional(),background:i,column_blocks:e.z.array(e.z.array(o)),column_gap:e.z.enum([`none`,`sm`,`md`,`lg`,`xl`]),container_type:e.z.enum([`full-width`,`container`,`container-sm`,`container-lg`,`container-xl`]),is_hero:e.z.boolean().optional(),padding:e.z.object({bottom:e.z.enum([`none`,`sm`,`md`,`lg`,`xl`]),top:e.z.enum([`none`,`sm`,`md`,`lg`,`xl`])}),responsive_columns:e.z.object({desktop:e.z.union([e.z.literal(1),e.z.literal(2),e.z.literal(3),e.z.literal(4)]),mobile:e.z.union([e.z.literal(1),e.z.literal(2)]),tablet:e.z.union([e.z.literal(1),e.z.literal(2),e.z.literal(3)])}),slider:e.z.boolean().optional(),slides:e.z.array(s).optional(),timeframe:e.z.number().optional(),vertical_alignment:e.z.enum([`start`,`center`,`end`,`stretch`]).optional()}),l={button:e.z.object({position:e.z.enum([`left`,`center`,`right`]).optional(),size:e.z.enum([`default`,`sm`,`lg`,`full`]).optional(),text:e.z.string(),url:e.z.string(),variant:e.z.enum([`default`,`outline`,`secondary`,`ghost`,`link`]).optional()}),cart:e.z.object({}),checkout:e.z.object({}),featured_product:e.z.object({imagePosition:e.z.enum([`left`,`right`]).default(`left`),productId:e.z.string().min(1),showBackground:e.z.boolean().default(!1)}),form:e.z.object({fields:e.z.array(e.z.object({field_type:e.z.enum([`text`,`email`,`tel`,`url`,`number`,`textarea`,`select`,`radio`,`checkbox`]),is_required:e.z.boolean(),label:e.z.string(),options:e.z.array(e.z.object({label:e.z.string(),value:e.z.string()})).optional(),placeholder:e.z.string().optional(),temp_id:e.z.string()})),form_key:e.z.string().optional(),recipient_email:e.z.string().email().optional(),submit_button_text:e.z.string(),success_message:e.z.string()}),heading:e.z.object({level:e.z.union([e.z.literal(1),e.z.literal(2),e.z.literal(3),e.z.literal(4),e.z.literal(5),e.z.literal(6)]),textAlign:e.z.enum([`left`,`center`,`right`,`justify`]).optional(),textColor:e.z.union([e.z.enum([`foreground`,`primary`,`secondary`,`accent`,`muted`,`destructive`,`background`]),e.z.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`),text_content:e.z.string()}),image:e.z.object({alt_text:e.z.string().optional(),caption:e.z.string().optional(),external_url:e.z.string().nullable().optional(),height:e.z.number().nullable().optional(),media_id:e.z.string().nullable().optional(),object_key:e.z.string().nullable().optional(),width:e.z.number().nullable().optional()}),posts_grid:e.z.object({columns:e.z.number().min(1).max(6),postsPerPage:e.z.number().min(1).max(50),showPagination:e.z.boolean(),title:e.z.string().optional()}),product_details:e.z.object({}),product_grid:e.z.object({categoryId:e.z.string().optional(),categoryIds:e.z.array(e.z.string()).max(20).optional(),limit:e.z.number().min(0).max(48).default(6),productIds:e.z.array(e.z.string()).max(24).optional(),showPagination:e.z.boolean().default(!1),title:e.z.string().optional(),type:e.z.enum([`latest`,`category`,`manual`]).default(`latest`)}),section:c,testimonial:e.z.object({author_name:e.z.string().min(1),author_title:e.z.string().optional(),image_url:e.z.string().url().optional().or(e.z.literal(``)),quote:e.z.string().min(1)}),text:e.z.object({html_content:e.z.string()}),video_embed:e.z.object({autoplay:e.z.boolean().optional(),controls:e.z.boolean().optional(),title:e.z.string().optional(),url:e.z.string()})};function u(e){return t.includes(e)}function d(e){return typeof e?.validateBlockContent==`function`?e.validateBlockContent:null}function f(e,t,n){let r=d(n);if(r)return r(e,t);let i=l[e].safeParse(t);return i.success?{errors:[],isValid:!0,warnings:[]}:{errors:i.error.issues.map(e=>{let t=e.path.join(`.`);return t?`${t}: ${e.message}`:e.message}),isValid:!1,warnings:[]}}function p(e){return Array.isArray(e.fields)?e.fields.filter(e=>!!e&&typeof e==`object`&&typeof e.key==`string`&&typeof e.type==`string`):[]}function m(e){return e==null||typeof e==`string`&&e.trim()===``||Array.isArray(e)&&e.length===0}function h(e,t){if(!t||typeof t!=`object`||Array.isArray(t))return{errors:[`content must be a JSON object of { field_key: value } pairs.`],isValid:!1,warnings:[]};let n=p(e),r=new Set(n.map(e=>e.key)),i=[],a=[];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)`}.`);for(let e of n){let n=t[e.key];if(m(n)){e.required&&i.push(`Field "${e.key}" is required.`);continue}if(e.type===`text`||e.type===`rich-text`){if(typeof n!=`string`){i.push(`Field "${e.key}" must be a string${e.type===`rich-text`?` of HTML`:``}.`);continue}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.`);continue}if(e.type===`image_r2`){let t=n;(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.`);continue}if(e.type===`db_relation`){let t=e=>typeof e==`string`||typeof e==`number`;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.`);continue}a.push(`Field "${e.key}" has an unrecognised type "${String(e.type)}"; it was not validated.`)}return{errors:i,isValid:i.length===0,warnings:a}}async function g(e){let{data:t,error:n}=await e.from(`custom_block_definitions`).select(`slug, name, fields`);if(n)throw Error(`Could not read the custom block definitions: ${typeof n==`object`&&n&&`message`in n?String(n.message):String(n)}`);return(Array.isArray(t)?t:[]).filter(e=>!!e&&typeof e.slug==`string`)}exports.availableCortexAiBlockTypes=t,exports.cortexAiBlockTypeSchema=n,exports.customBlockSlugPatternSchema=a,exports.fallbackBlockSchemas=l,exports.isValidBlockType=u,exports.loadCustomBlockDefinitions=g,exports.readCustomBlockFields=p,exports.sectionBlockFallbackSchema=c,exports.validateCortexBlockContent=f,exports.validateCustomBlockInstanceContent=h;