@nextblock-cms/cortex 0.14.6 → 0.15.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.
@@ -0,0 +1,175 @@
1
+ import { z } from './zod-config';
2
+ /**
3
+ * The pieces a site needs before content can be built on top of it: media,
4
+ * locales, and product categories.
5
+ *
6
+ * Each of these existed in the CMS but had no tool, which made them hard floors on
7
+ * what could be produced in one pass — an agent could not reuse an image it had
8
+ * already imported, could not add a second language, and could not create the
9
+ * category a product grid filters by.
10
+ */
11
+ type ContentOpsToolContext = {
12
+ actorFromOrphanedToken?: boolean;
13
+ actorUserId?: string | null;
14
+ importExternalImage?: (input: {
15
+ altText?: string;
16
+ url: string;
17
+ }) => Promise<{
18
+ id: string;
19
+ } | {
20
+ error: string;
21
+ }>;
22
+ latestUserMessage?: string | null;
23
+ revalidatePath?: (path: string, type?: 'layout' | 'page') => void;
24
+ skipConfirmation?: boolean;
25
+ supabase?: {
26
+ from: (table: string) => any;
27
+ };
28
+ };
29
+ export declare const listMediaInputSchema: z.ZodObject<{
30
+ limit: z.ZodDefault<z.ZodNumber>;
31
+ query: z.ZodOptional<z.ZodString>;
32
+ }, z.core.$strict>;
33
+ export declare const uploadMediaInputSchema: z.ZodObject<{
34
+ altText: z.ZodOptional<z.ZodString>;
35
+ url: z.ZodString;
36
+ }, z.core.$strict>;
37
+ export declare function executeListMedia(input: z.infer<typeof listMediaInputSchema>, context?: ContentOpsToolContext): Promise<{
38
+ count: any;
39
+ media: any;
40
+ success: boolean;
41
+ }>;
42
+ export declare function executeUploadMedia(input: z.infer<typeof uploadMediaInputSchema>, context?: ContentOpsToolContext): Promise<{
43
+ mediaId: string;
44
+ mutationExecuted: boolean;
45
+ success: boolean;
46
+ }>;
47
+ export declare const manageLanguageInputSchema: z.ZodObject<{
48
+ code: z.ZodString;
49
+ is_active: z.ZodDefault<z.ZodBoolean>;
50
+ is_default: z.ZodDefault<z.ZodBoolean>;
51
+ name: z.ZodString;
52
+ }, z.core.$strict>;
53
+ export declare function executeManageLanguage(input: z.infer<typeof manageLanguageInputSchema>, context?: ContentOpsToolContext): Promise<{
54
+ code: string;
55
+ created: boolean;
56
+ languageId: number;
57
+ mutationExecuted: boolean;
58
+ success: boolean;
59
+ }>;
60
+ export declare const manageProductCategoryInputSchema: z.ZodObject<{
61
+ action: z.ZodDefault<z.ZodEnum<{
62
+ delete: "delete";
63
+ upsert: "upsert";
64
+ }>>;
65
+ description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
66
+ name: z.ZodString;
67
+ name_translations: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
68
+ productSlugs: z.ZodOptional<z.ZodArray<z.ZodString>>;
69
+ slug: z.ZodOptional<z.ZodString>;
70
+ }, z.core.$strict>;
71
+ export declare function executeManageProductCategory(input: z.infer<typeof manageProductCategoryInputSchema>, context?: ContentOpsToolContext): Promise<{
72
+ message: string;
73
+ mutationExecuted: boolean;
74
+ success: boolean;
75
+ action?: undefined;
76
+ slug?: undefined;
77
+ categoryId?: undefined;
78
+ created?: undefined;
79
+ linkedProducts?: undefined;
80
+ } | {
81
+ action: string;
82
+ mutationExecuted: boolean;
83
+ slug: string;
84
+ success: boolean;
85
+ message?: undefined;
86
+ categoryId?: undefined;
87
+ created?: undefined;
88
+ linkedProducts?: undefined;
89
+ } | {
90
+ categoryId: string;
91
+ created: boolean;
92
+ linkedProducts: number;
93
+ mutationExecuted: boolean;
94
+ slug: string;
95
+ success: boolean;
96
+ message?: undefined;
97
+ action?: undefined;
98
+ }>;
99
+ export declare const listProductCategoriesInputSchema: z.ZodObject<{}, z.core.$strict>;
100
+ export declare function executeListProductCategories(_input: unknown, context?: ContentOpsToolContext): Promise<{
101
+ categories: any;
102
+ count: any;
103
+ success: boolean;
104
+ }>;
105
+ export declare function createCortexContentOpsTools(context?: ContentOpsToolContext): {
106
+ list_media: import('ai').Tool<{
107
+ limit: number;
108
+ query?: string | undefined;
109
+ }, {
110
+ count: any;
111
+ media: any;
112
+ success: boolean;
113
+ }>;
114
+ list_product_categories: import('ai').Tool<Record<string, never>, {
115
+ categories: any;
116
+ count: any;
117
+ success: boolean;
118
+ }>;
119
+ manage_language: import('ai').Tool<{
120
+ code: string;
121
+ is_active: boolean;
122
+ is_default: boolean;
123
+ name: string;
124
+ }, {
125
+ code: string;
126
+ created: boolean;
127
+ languageId: number;
128
+ mutationExecuted: boolean;
129
+ success: boolean;
130
+ }>;
131
+ manage_product_category: import('ai').Tool<{
132
+ action: "delete" | "upsert";
133
+ name: string;
134
+ description?: string | null | undefined;
135
+ name_translations?: Record<string, string> | undefined;
136
+ productSlugs?: string[] | undefined;
137
+ slug?: string | undefined;
138
+ }, {
139
+ message: string;
140
+ mutationExecuted: boolean;
141
+ success: boolean;
142
+ action?: undefined;
143
+ slug?: undefined;
144
+ categoryId?: undefined;
145
+ created?: undefined;
146
+ linkedProducts?: undefined;
147
+ } | {
148
+ action: string;
149
+ mutationExecuted: boolean;
150
+ slug: string;
151
+ success: boolean;
152
+ message?: undefined;
153
+ categoryId?: undefined;
154
+ created?: undefined;
155
+ linkedProducts?: undefined;
156
+ } | {
157
+ categoryId: string;
158
+ created: boolean;
159
+ linkedProducts: number;
160
+ mutationExecuted: boolean;
161
+ slug: string;
162
+ success: boolean;
163
+ message?: undefined;
164
+ action?: undefined;
165
+ }>;
166
+ upload_media: import('ai').Tool<{
167
+ url: string;
168
+ altText?: string | undefined;
169
+ }, {
170
+ mediaId: string;
171
+ mutationExecuted: boolean;
172
+ success: boolean;
173
+ }>;
174
+ };
175
+ export {};
@@ -0,0 +1,211 @@
1
+ import { tool as m } from "ai";
2
+ import "./zod-config.es.js";
3
+ import { z as r } from "zod";
4
+ const $ = "id, file_name, object_key, file_type, width, height, description, folder, created_at";
5
+ function f(e) {
6
+ if (!e?.supabase)
7
+ throw new Error("No database connection is available for this tool.");
8
+ return e.supabase;
9
+ }
10
+ function c(e) {
11
+ return e ? e instanceof Error ? e.message : typeof e == "object" && "message" in e ? String(e.message) : String(e) : "unknown error";
12
+ }
13
+ function _(e) {
14
+ return e.normalize("NFD").replace(new RegExp("\\p{Diacritic}", "gu"), "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
15
+ }
16
+ const x = r.strictObject({
17
+ limit: r.number().int().min(1).max(100).default(30),
18
+ query: r.string().trim().max(120).optional().describe('Filter on file name or alt text, e.g. "wormwood" or "laboratory".')
19
+ }), E = r.strictObject({
20
+ altText: r.string().trim().max(300).optional().describe("Alt text describing the image. Write real alt text — it is what screen readers announce and what search engines index."),
21
+ url: r.string().trim().min(1).max(2048).describe("Public https URL of the image to bring into the media library.")
22
+ });
23
+ async function v(e, i) {
24
+ const t = x.parse(e);
25
+ let a = f(i).from("media").select($).order("created_at", { ascending: !1 }).limit(t.limit);
26
+ if (t.query) {
27
+ const s = `%${t.query}%`;
28
+ a = a.or(`file_name.ilike.${s},description.ilike.${s}`);
29
+ }
30
+ const { data: u, error: l } = await a;
31
+ if (l)
32
+ throw new Error(`Could not read the media library: ${c(l)}`);
33
+ return { count: (u ?? []).length, media: u ?? [], success: !0 };
34
+ }
35
+ async function I(e, i) {
36
+ const t = E.parse(e), o = i?.importExternalImage;
37
+ if (!o)
38
+ throw new Error("Media import is not available on this connection.");
39
+ const a = await o({
40
+ ...t.altText ? { altText: t.altText } : {},
41
+ url: t.url
42
+ });
43
+ if ("error" in a)
44
+ throw new Error(`Could not import that image: ${a.error}`);
45
+ return { mediaId: a.id, mutationExecuted: !0, success: !0 };
46
+ }
47
+ const C = r.strictObject({
48
+ code: r.string().trim().min(2).max(10).describe('Locale code, e.g. "fr", "es", "de". Re-using an existing code updates that language.'),
49
+ is_active: r.boolean().default(!0).describe("Inactive languages are hidden from the public switcher."),
50
+ is_default: r.boolean().default(!1).describe("Make this the site default. Only one language can be default; setting it clears the others."),
51
+ name: r.string().trim().min(1).max(80).describe('Display name, e.g. "Français".')
52
+ });
53
+ async function L(e, i) {
54
+ const t = C.parse(e), o = f(i), a = t.code.toLowerCase(), { data: u } = await o.from("languages").select("id, code").eq("code", a).maybeSingle(), l = {
55
+ code: a,
56
+ is_active: t.is_active,
57
+ name: t.name
58
+ };
59
+ let s = u?.id;
60
+ if (s) {
61
+ const { error: d } = await o.from("languages").update(l).eq("id", s);
62
+ if (d)
63
+ throw new Error(`Could not update the "${a}" language: ${c(d)}`);
64
+ } else {
65
+ const { data: d, error: n } = await o.from("languages").insert(l).select("id").single();
66
+ if (n || !d?.id)
67
+ throw new Error(`Could not create the "${a}" language: ${c(n)}`);
68
+ s = d.id;
69
+ }
70
+ if (t.is_default) {
71
+ const { error: d } = await o.from("languages").update({ is_default: !1 }).neq("id", s);
72
+ if (d)
73
+ throw new Error(`Could not clear the previous default language: ${c(d)}`);
74
+ const { error: n } = await o.from("languages").update({ is_default: !0 }).eq("id", s);
75
+ if (n)
76
+ throw new Error(`Could not set the default language: ${c(n)}`);
77
+ }
78
+ try {
79
+ i?.revalidatePath?.("/", "layout");
80
+ } catch {
81
+ }
82
+ return {
83
+ code: a,
84
+ created: !u,
85
+ languageId: s,
86
+ mutationExecuted: !0,
87
+ success: !0
88
+ };
89
+ }
90
+ const S = r.strictObject({
91
+ action: r.enum(["upsert", "delete"]).default("upsert"),
92
+ description: r.string().max(1e3).nullable().optional(),
93
+ name: r.string().trim().min(1).max(120).describe('Category name, e.g. "Digestive Health".'),
94
+ name_translations: r.record(r.string(), r.string()).optional().describe('Translated names keyed by locale code, e.g. { "fr": "Santé digestive" }.'),
95
+ productSlugs: r.array(r.string().trim().min(1).max(300)).max(100).optional().describe("Product slugs to place in this category. Replaces the category's current membership."),
96
+ slug: r.string().trim().min(1).max(120).optional().describe("URL slug. Derived from the name when omitted. Re-using a slug updates that category.")
97
+ });
98
+ async function k(e, i) {
99
+ const t = S.parse(e), o = f(i), a = t.slug ? _(t.slug) : _(t.name), { data: u } = await o.from("categories").select("id, name, slug").eq("slug", a).maybeSingle();
100
+ if (t.action === "delete") {
101
+ if (!u?.id)
102
+ return {
103
+ message: `No category with slug "${a}".`,
104
+ mutationExecuted: !1,
105
+ success: !1
106
+ };
107
+ const { error: n } = await o.from("categories").delete().eq("id", u.id);
108
+ if (n)
109
+ throw new Error(`Could not delete the category: ${c(n)}`);
110
+ return { action: "delete", mutationExecuted: !0, slug: a, success: !0 };
111
+ }
112
+ const l = {
113
+ name: t.name,
114
+ slug: a,
115
+ ...t.description !== void 0 ? { description: t.description } : {},
116
+ ...t.name_translations ? { name_translations: t.name_translations } : {}
117
+ };
118
+ let s = u?.id;
119
+ if (s) {
120
+ const { error: n } = await o.from("categories").update(l).eq("id", s);
121
+ if (n)
122
+ throw new Error(`Could not update the category: ${c(n)}`);
123
+ } else {
124
+ const { data: n, error: g } = await o.from("categories").insert(l).select("id").single();
125
+ if (g || !n?.id)
126
+ throw new Error(`Could not create the category: ${c(g)}`);
127
+ s = n.id;
128
+ }
129
+ let d = 0;
130
+ if (t.productSlugs) {
131
+ const { data: n, error: g } = await o.from("products").select("id, slug").in("slug", t.productSlugs);
132
+ if (g)
133
+ throw new Error(`Could not resolve those products: ${c(g)}`);
134
+ const p = n ?? [], y = t.productSlugs.filter(
135
+ (h) => !p.some((w) => w.slug === h)
136
+ );
137
+ if (y.length > 0)
138
+ throw new Error(`No product found for slug(s): ${y.join(", ")}.`);
139
+ const { error: b } = await o.from("product_categories").delete().eq("category_id", s);
140
+ if (b)
141
+ throw new Error(`Could not clear the category's products: ${c(b)}`);
142
+ if (p.length > 0) {
143
+ const { error: h } = await o.from("product_categories").insert(p.map((w) => ({ category_id: s, product_id: w.id })));
144
+ if (h)
145
+ throw new Error(`Could not add products to the category: ${c(h)}`);
146
+ d = p.length;
147
+ }
148
+ }
149
+ return {
150
+ categoryId: s,
151
+ created: !u,
152
+ linkedProducts: d,
153
+ mutationExecuted: !0,
154
+ slug: a,
155
+ success: !0
156
+ };
157
+ }
158
+ const q = r.strictObject({});
159
+ async function R(e, i) {
160
+ const t = f(i), { data: o, error: a } = await t.from("categories").select("id, name, slug, description, name_translations").order("name");
161
+ if (a)
162
+ throw new Error(`Could not read the categories: ${c(a)}`);
163
+ return { categories: o ?? [], count: (o ?? []).length, success: !0 };
164
+ }
165
+ function O(e) {
166
+ return {
167
+ list_media: m({
168
+ description: "Browse the media library: file names, alt text, dimensions, and media ids. Read-only. Call this BEFORE importing an image so you reuse what is already stored instead of creating a duplicate — the returned `id` can be passed anywhere a media id or image reference is accepted (feature_image_id, product images, an image block).",
169
+ execute: (i) => v(i, e),
170
+ inputSchema: x,
171
+ strict: !0
172
+ }),
173
+ list_product_categories: m({
174
+ description: "List the product categories, with their slugs and translated names. Read-only. Use before creating one so an existing category is reused, and to get ids for a product_grid block filtered by category.",
175
+ execute: (i) => R(i, e),
176
+ inputSchema: q,
177
+ strict: !0
178
+ }),
179
+ manage_language: m({
180
+ description: "Add or update a site language, so the CMS can hold content in that locale. Creating the language is the FIRST step of making a site multilingual — translate_page cannot target a locale that does not exist yet. Re-using a code updates that language; set is_default to change the site default.",
181
+ execute: (i) => L(i, e),
182
+ inputSchema: C,
183
+ strict: !0
184
+ }),
185
+ manage_product_category: m({
186
+ description: "Create, update, or delete a product category, and optionally set exactly which products belong to it by slug. Categories are what a product_grid block filters on, so create these before building a shop page that shows one section of the catalogue. Passing productSlugs REPLACES the category's membership.",
187
+ execute: (i) => k(i, e),
188
+ inputSchema: S,
189
+ strict: !0
190
+ }),
191
+ upload_media: m({
192
+ description: "Import an image from a public https URL into the media library and return its media id, without attaching it to anything. Useful when you want one asset reused across several places — otherwise passing the URL straight to create_cms_product `images` or a page/post `feature_image_id` imports it in the same call. Check list_media first to avoid duplicates.",
193
+ execute: (i) => I(i, e),
194
+ inputSchema: E,
195
+ strict: !0
196
+ })
197
+ };
198
+ }
199
+ export {
200
+ O as createCortexContentOpsTools,
201
+ v as executeListMedia,
202
+ R as executeListProductCategories,
203
+ L as executeManageLanguage,
204
+ k as executeManageProductCategory,
205
+ I as executeUploadMedia,
206
+ x as listMediaInputSchema,
207
+ q as listProductCategoriesInputSchema,
208
+ C as manageLanguageInputSchema,
209
+ S as manageProductCategoryInputSchema,
210
+ E as uploadMediaInputSchema
211
+ };
@@ -1 +1 @@
1
- "use strict";var z=Object.create;var h=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var U=Object.getPrototypeOf,D=Object.prototype.hasOwnProperty;var I=(e,t,s,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of T(t))!D.call(e,o)&&o!==s&&h(e,o,{get:()=>t[o],enumerable:!(i=A(t,o))||i.enumerable});return e};var L=(e,t,s)=>(s=e!=null?z(U(e)):{},I(t||!e||!e.__esModule?h(s,"default",{value:e,enumerable:!0}):s,e));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("ai");require("./zod-config.cjs.js");const r=require("zod"),k="id, slug, name, description, fields, layout_schema, is_original",C=r.z.strictObject({context:r.z.string().trim().max(3e3).optional().describe("Optional extra constraints or brand/style guidance for the generated block."),prompt:r.z.string().trim().min(3).max(4e3).describe('Natural-language description of the custom block, including the fields it needs and the visual style. Example: "A product card with a title, image, price, and a button that links to the product page."')}),w=r.z.strictObject({prompt:r.z.string().trim().min(3).max(4e3).describe("Description of the changes to apply. The block is regenerated using its existing definition as context."),slug:r.z.string().trim().min(1).max(120).describe("Slug of the existing custom block to edit.")}),S=r.z.strictObject({slug:r.z.string().trim().min(1).max(120).describe("Slug of the custom block definition to delete.")}),_=r.z.strictObject({query:r.z.string().trim().max(120).optional().describe("Optional text filter on name or slug.")});function l(e){if(!e?.supabase)throw new Error("A Supabase service client is required to manage custom block definitions.");return e.supabase}function g(e){if(!e?.actorUserId)throw new Error("Managing custom block definitions requires an authenticated admin actor.");return e.actorUserId}function y(e){return JSON.parse(JSON.stringify(e))}function f(e){const t=Array.isArray(e?.fields)?e.fields:[];return{fieldCount:t.length,fields:t.map(s=>({key:s?.key,label:s?.label,type:s?.type})),id:e?.id,name:e?.name,slug:e?.slug}}function E(e,t){const s=t?.cortexAiApiKey||void 0;return{apiKey:s,context:e.context,modelSelection:s&&t?.cortexAiModelSelection?t.cortexAiModelSelection:void 0,prompt:e.prompt}}function p(e){try{const{revalidatePath:t,revalidateTag:s}=require("next/cache");s("custom-block-definitions","max"),e?.id&&s(`custom-block-definitions:${e.id}`,"max"),e?.slug&&s(`custom-block-definitions:${e.slug}`,"max"),s("dynamic-layout-engine","max"),t("/cms/custom-blocks"),t("/cms/blocks")}catch{}}function x(e){return(e||"").replace(/\s+/g," ").trim().toUpperCase()}function $(e){return`CONFIRM DELETE CUSTOM BLOCK ${e.toUpperCase()}`}function P(e,t){return e?.skipConfirmation?!0:x(e?.latestUserMessage).includes(x(t))}function m(e){if(e&&typeof e=="object"){const t=e;if(t.code==="23505")return"A custom block with that slug already exists. Choose a different name or edit the existing one.";if(typeof t.message=="string"&&t.message)return t.message}return e instanceof Error?e.message:"Unknown error."}async function B(e,t){try{const s=l(t);g(t);const[{generateCortexWidgetDefinition:i},{insertCortexWidgetDefinition:o}]=await Promise.all([Promise.resolve().then(()=>require("./ai-cortex-widget-builder.cjs.js")),Promise.resolve().then(()=>require("./cortex-widget-registry.cjs.js"))]),a=await i(E(e,t)),n=await o(s,a.definition);return p(n),{definition:f(n),editUrl:`/cms/custom-blocks/${n.id}/edit`,mutationExecuted:!0,success:!0}}catch(s){return{mutationExecuted:!1,message:m(s),success:!1}}}async function q(e,t){try{const s=l(t);g(t);const{data:i}=await s.from("custom_block_definitions").select(k).eq("slug",e.slug).maybeSingle();if(!i)return{mutationExecuted:!1,message:`No custom block found with slug "${e.slug}".`,success:!1};const[{generateCortexWidgetDefinition:o},{customBlockDefinitionCreateSchema:a}]=await Promise.all([Promise.resolve().then(()=>require("./ai-cortex-widget-builder.cjs.js")),import("@nextblock-cms/utils/custom-blocks")]),n=await o(E({context:`You are editing an existing custom block named "${i.name}". Keep its overall purpose and only apply the requested changes. Existing definition: ${JSON.stringify({fields:i.fields,layout_schema:i.layout_schema,name:i.name})}`,prompt:e.prompt},t)),c=a.parse({...n.definition,is_original:i.is_original,slug:i.slug}),{data:d,error:b}=await s.from("custom_block_definitions").update({description:c.description,fields:y(c.fields),layout_schema:y(c.layout_schema),name:c.name}).eq("id",i.id).select(k).single();return b||!d?{mutationExecuted:!1,message:b?.message??"Failed to update custom block.",success:!1}:(p(d),{definition:f(d),editUrl:`/cms/custom-blocks/${i.id}/edit`,mutationExecuted:!0,success:!0})}catch(s){return{mutationExecuted:!1,message:m(s),success:!1}}}async function O(e,t){try{const s=l(t);g(t);const{data:i}=await s.from("custom_block_definitions").select("id, slug, name").eq("slug",e.slug).maybeSingle();if(!i)return{mutationExecuted:!1,message:`No custom block found with slug "${e.slug}".`,success:!1};const o=$(i.slug);if(!P(t,o))return{confirmationPhrase:o,mutationExecuted:!1,preview:{summary:`Delete the custom block "${i.name}" (${i.slug}). Pages still using it will stop rendering it until replaced. This cannot be undone.`},requiresConfirmation:!0,success:!0};const{error:a}=await s.from("custom_block_definitions").delete().eq("id",i.id);return a?{mutationExecuted:!1,message:`Failed to delete custom block: ${a.message}`,success:!1}:(p(i),{deleted:{name:i.name,slug:i.slug},mutationExecuted:!0,success:!0})}catch(s){return{mutationExecuted:!1,message:m(s),success:!1}}}async function v(e,t){try{const s=l(t),{data:i,error:o}=await s.from("custom_block_definitions").select("id, slug, name, description, fields, is_original").order("name",{ascending:!0});if(o)return{message:o.message,success:!1};let a=Array.isArray(i)?i:[];if(e.query){const n=e.query.toLowerCase();a=a.filter(c=>String(c.name||"").toLowerCase().includes(n)||String(c.slug||"").toLowerCase().includes(n))}return{blocks:a.map(n=>f(n)),count:a.length,success:!0}}catch(s){return{message:m(s),success:!1}}}function M(e){return{create_custom_block:u.tool({description:'Create a brand-new reusable custom block definition from a natural-language description (for example "a product card with title, image, price, and a button linking to the product page"). This is a GLOBAL block-library builder and does NOT require an open page, post, or product. It generates the field schema and Tailwind layout and saves it so the block can be added to any page afterward. Additive and reversible; executes immediately without a confirmation phrase.',execute:t=>B(t,e),inputSchema:C,strict:!0}),delete_custom_block:u.tool({description:"Delete a custom block definition by slug. Mutating: first returns a confirmation phrase; only executes after the user replies with the exact phrase. Use list_custom_blocks first if you are unsure of the slug.",execute:t=>O(t,e),inputSchema:S,strict:!0}),list_custom_blocks:u.tool({description:"List the existing custom block definitions (slug, name, and fields). Read-only and does not require page context. Use it to find the slug of a block to edit or delete.",execute:t=>v(t,e),inputSchema:_,strict:!0}),update_custom_block:u.tool({description:"Edit an existing custom block definition (identified by slug) from a new natural-language description. The block is regenerated with its current definition as context and keeps its slug so existing placements keep working. Executes immediately.",execute:t=>q(t,e),inputSchema:w,strict:!0})}}exports.createCortexCustomBlockTools=M;exports.createCustomBlockInputSchema=C;exports.deleteCustomBlockInputSchema=S;exports.executeCreateCustomBlock=B;exports.executeDeleteCustomBlock=O;exports.executeListCustomBlocks=v;exports.executeUpdateCustomBlock=q;exports.listCustomBlocksInputSchema=_;exports.updateCustomBlockInputSchema=w;
1
+ "use strict";var v=Object.create;var h=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var U=Object.getPrototypeOf,$=Object.prototype.hasOwnProperty;var z=(e,t,s,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of D(t))!$.call(e,o)&&o!==s&&h(e,o,{get:()=>t[o],enumerable:!(i=A(t,o))||i.enumerable});return e};var L=(e,t,s)=>(s=e!=null?v(U(e)):{},z(t||!e||!e.__esModule?h(s,"default",{value:e,enumerable:!0}):s,e));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("ai");require("./zod-config.cjs.js");const r=require("zod"),k="id, slug, name, description, fields, layout_schema, is_original",w=r.z.strictObject({context:r.z.string().trim().max(3e3).optional().describe("Optional extra constraints or brand/style guidance for the generated block."),prompt:r.z.string().trim().min(3).max(4e3).describe('Natural-language description of the custom block, including the fields it needs and the visual style. Example: "A product card with a title, image, price, and a button that links to the product page."')}),S=r.z.strictObject({prompt:r.z.string().trim().min(3).max(4e3).describe("Description of the changes to apply. The block is regenerated using its existing definition as context."),slug:r.z.string().trim().min(1).max(120).describe("Slug of the existing custom block to edit.")}),_=r.z.strictObject({slug:r.z.string().trim().min(1).max(120).describe("Slug of the custom block definition to delete.")}),E=r.z.strictObject({query:r.z.string().trim().max(120).optional().describe("Optional text filter on name or slug.")});function l(e){if(!e?.supabase)throw new Error("A Supabase service client is required to manage custom block definitions.");return e.supabase}function f(e){if(!e?.actorUserId)throw new Error("Managing custom block definitions requires an authenticated admin actor.");return e.actorUserId}function y(e){return JSON.parse(JSON.stringify(e))}function g(e){const t=Array.isArray(e?.fields)?e.fields:[];return{fieldCount:t.length,fields:t.map(s=>({key:s?.key,label:s?.label,type:s?.type})),id:e?.id,name:e?.name,slug:e?.slug}}const x=24e3;function N(e){const t=`You are editing an existing custom block named "${e.name??"Untitled"}". Keep its overall purpose and only apply the requested changes.`,s=`${t} Existing definition: ${JSON.stringify({fields:e.fields,layout_schema:e.layout_schema,name:e.name})}`;return s.length<=x?s:`${t} Existing fields: ${JSON.stringify({fields:e.fields,name:e.name})} (The existing layout was too large to include — rebuild a layout that renders these fields.)`.slice(0,x)}function B(e,t){const s=t?.cortexAiApiKey||void 0;return{apiKey:s,context:e.context,modelSelection:s&&t?.cortexAiModelSelection?t.cortexAiModelSelection:void 0,prompt:e.prompt}}function p(e){try{const{revalidatePath:t,revalidateTag:s}=require("next/cache");s("custom-block-definitions","max"),e?.id&&s(`custom-block-definitions:${e.id}`,"max"),e?.slug&&s(`custom-block-definitions:${e.slug}`,"max"),s("dynamic-layout-engine","max"),t("/cms/custom-blocks"),t("/cms/blocks")}catch{}}function C(e){return(e||"").replace(/\s+/g," ").trim().toUpperCase()}function P(e){return`CONFIRM DELETE CUSTOM BLOCK ${e.toUpperCase()}`}function M(e,t){return e?.skipConfirmation?!0:C(e?.latestUserMessage).includes(C(t))}function m(e){if(e&&typeof e=="object"){const t=e;if(t.code==="23505")return"A custom block with that slug already exists. Choose a different name or edit the existing one.";if(typeof t.message=="string"&&t.message)return t.message}return e instanceof Error?e.message:"Unknown error."}async function q(e,t){try{const s=l(t);f(t);const[{generateCortexWidgetDefinition:i},{insertCortexWidgetDefinition:o}]=await Promise.all([Promise.resolve().then(()=>require("./ai-cortex-widget-builder.cjs.js")),Promise.resolve().then(()=>require("./cortex-widget-registry.cjs.js"))]),n=await i(B(e,t)),a=await o(s,n.definition);return p(a),{definition:g(a),editUrl:`/cms/custom-blocks/${a.id}/edit`,mutationExecuted:!0,success:!0}}catch(s){return{mutationExecuted:!1,message:m(s),success:!1}}}async function O(e,t){try{const s=l(t);f(t);const{data:i}=await s.from("custom_block_definitions").select(k).eq("slug",e.slug).maybeSingle();if(!i)return{mutationExecuted:!1,message:`No custom block found with slug "${e.slug}".`,success:!1};const[{generateCortexWidgetDefinition:o},{customBlockDefinitionCreateSchema:n}]=await Promise.all([Promise.resolve().then(()=>require("./ai-cortex-widget-builder.cjs.js")),import("@nextblock-cms/utils/custom-blocks")]),a=await o(B({context:N(i),prompt:e.prompt},t)),c=n.parse({...a.definition,is_original:i.is_original,slug:i.slug}),{data:d,error:b}=await s.from("custom_block_definitions").update({description:c.description,fields:y(c.fields),layout_schema:y(c.layout_schema),name:c.name}).eq("id",i.id).select(k).single();return b||!d?{mutationExecuted:!1,message:b?.message??"Failed to update custom block.",success:!1}:(p(d),{definition:g(d),editUrl:`/cms/custom-blocks/${i.id}/edit`,mutationExecuted:!0,success:!0})}catch(s){return{mutationExecuted:!1,message:m(s),success:!1}}}async function T(e,t){try{const s=l(t);f(t);const{data:i}=await s.from("custom_block_definitions").select("id, slug, name").eq("slug",e.slug).maybeSingle();if(!i)return{mutationExecuted:!1,message:`No custom block found with slug "${e.slug}".`,success:!1};const o=P(i.slug);if(!M(t,o))return{confirmationPhrase:o,mutationExecuted:!1,preview:{summary:`Delete the custom block "${i.name}" (${i.slug}). Pages still using it will stop rendering it until replaced. This cannot be undone.`},requiresConfirmation:!0,success:!0};const{error:n}=await s.from("custom_block_definitions").delete().eq("id",i.id);return n?{mutationExecuted:!1,message:`Failed to delete custom block: ${n.message}`,success:!1}:(p(i),{deleted:{name:i.name,slug:i.slug},mutationExecuted:!0,success:!0})}catch(s){return{mutationExecuted:!1,message:m(s),success:!1}}}async function I(e,t){try{const s=l(t),{data:i,error:o}=await s.from("custom_block_definitions").select("id, slug, name, description, fields, is_original").order("name",{ascending:!0});if(o)return{message:o.message,success:!1};let n=Array.isArray(i)?i:[];if(e.query){const a=e.query.toLowerCase();n=n.filter(c=>String(c.name||"").toLowerCase().includes(a)||String(c.slug||"").toLowerCase().includes(a))}return{blocks:n.map(a=>g(a)),count:n.length,success:!0}}catch(s){return{message:m(s),success:!1}}}function j(e){return{create_custom_block:u.tool({description:'Create a brand-new reusable custom block definition from a natural-language description (for example "a product card with title, image, price, and a button linking to the product page"). This is a GLOBAL block-library builder and does NOT require an open page, post, or product. It generates the field schema and Tailwind layout and saves it so the block can be added to any page afterward. Additive and reversible; executes immediately without a confirmation phrase.',execute:t=>q(t,e),inputSchema:w,strict:!0}),delete_custom_block:u.tool({description:"Delete a custom block definition by slug. Mutating: first returns a confirmation phrase; only executes after the user replies with the exact phrase. Use list_custom_blocks first if you are unsure of the slug.",execute:t=>T(t,e),inputSchema:_,strict:!0}),list_custom_blocks:u.tool({description:"List the existing custom block definitions (slug, name, and fields). Read-only and does not require page context. Use it to find the slug of a block to edit or delete.",execute:t=>I(t,e),inputSchema:E,strict:!0}),update_custom_block:u.tool({description:"Edit an existing custom block definition (identified by slug) from a new natural-language description. The block is regenerated with its current definition as context and keeps its slug so existing placements keep working. Executes immediately.",execute:t=>O(t,e),inputSchema:S,strict:!0})}}exports.createCortexCustomBlockTools=j;exports.createCustomBlockInputSchema=w;exports.deleteCustomBlockInputSchema=_;exports.executeCreateCustomBlock=q;exports.executeDeleteCustomBlock=T;exports.executeListCustomBlocks=I;exports.executeUpdateCustomBlock=O;exports.listCustomBlocksInputSchema=E;exports.updateCustomBlockInputSchema=S;