@nextblock-cms/cortex 0.14.5 → 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,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;
@@ -1,25 +1,25 @@
1
1
  import { tool as u } from "ai";
2
2
  import "./zod-config.es.js";
3
- import { z as n } from "zod";
4
- const h = "id, slug, name, description, fields, layout_schema, is_original", C = n.strictObject({
5
- context: n.string().trim().max(3e3).optional().describe("Optional extra constraints or brand/style guidance for the generated block."),
6
- prompt: n.string().trim().min(3).max(4e3).describe(
3
+ import { z as a } from "zod";
4
+ const h = "id, slug, name, description, fields, layout_schema, is_original", w = a.strictObject({
5
+ context: a.string().trim().max(3e3).optional().describe("Optional extra constraints or brand/style guidance for the generated block."),
6
+ prompt: a.string().trim().min(3).max(4e3).describe(
7
7
  '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."'
8
8
  )
9
- }), w = n.strictObject({
10
- prompt: n.string().trim().min(3).max(4e3).describe("Description of the changes to apply. The block is regenerated using its existing definition as context."),
11
- slug: n.string().trim().min(1).max(120).describe("Slug of the existing custom block to edit.")
12
- }), _ = n.strictObject({
13
- slug: n.string().trim().min(1).max(120).describe("Slug of the custom block definition to delete.")
14
- }), S = n.strictObject({
15
- query: n.string().trim().max(120).optional().describe("Optional text filter on name or slug.")
9
+ }), _ = a.strictObject({
10
+ prompt: a.string().trim().min(3).max(4e3).describe("Description of the changes to apply. The block is regenerated using its existing definition as context."),
11
+ slug: a.string().trim().min(1).max(120).describe("Slug of the existing custom block to edit.")
12
+ }), E = a.strictObject({
13
+ slug: a.string().trim().min(1).max(120).describe("Slug of the custom block definition to delete.")
14
+ }), S = a.strictObject({
15
+ query: a.string().trim().max(120).optional().describe("Optional text filter on name or slug.")
16
16
  });
17
17
  function l(e) {
18
18
  if (!e?.supabase)
19
19
  throw new Error("A Supabase service client is required to manage custom block definitions.");
20
20
  return e.supabase;
21
21
  }
22
- function g(e) {
22
+ function f(e) {
23
23
  if (!e?.actorUserId)
24
24
  throw new Error("Managing custom block definitions requires an authenticated admin actor.");
25
25
  return e.actorUserId;
@@ -27,7 +27,7 @@ function g(e) {
27
27
  function k(e) {
28
28
  return JSON.parse(JSON.stringify(e));
29
29
  }
30
- function f(e) {
30
+ function g(e) {
31
31
  const t = Array.isArray(e?.fields) ? e.fields : [];
32
32
  return {
33
33
  fieldCount: t.length,
@@ -37,7 +37,19 @@ function f(e) {
37
37
  slug: e?.slug
38
38
  };
39
39
  }
40
- function x(e, t) {
40
+ const y = 24e3;
41
+ function O(e) {
42
+ 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({
43
+ fields: e.fields,
44
+ layout_schema: e.layout_schema,
45
+ name: e.name
46
+ })}`;
47
+ return s.length <= y ? s : `${t} Existing fields: ${JSON.stringify({
48
+ fields: e.fields,
49
+ name: e.name
50
+ })} (The existing layout was too large to include — rebuild a layout that renders these fields.)`.slice(0, y);
51
+ }
52
+ function C(e, t) {
41
53
  const s = t?.cortexAiApiKey || void 0;
42
54
  return {
43
55
  apiKey: s,
@@ -53,16 +65,16 @@ function p(e) {
53
65
  } catch {
54
66
  }
55
67
  }
56
- function y(e) {
68
+ function x(e) {
57
69
  return (e || "").replace(/\s+/g, " ").trim().toUpperCase();
58
70
  }
59
- function E(e) {
71
+ function T(e) {
60
72
  return `CONFIRM DELETE CUSTOM BLOCK ${e.toUpperCase()}`;
61
73
  }
62
74
  function q(e, t) {
63
- return e?.skipConfirmation ? !0 : y(e?.latestUserMessage).includes(y(t));
75
+ return e?.skipConfirmation ? !0 : x(e?.latestUserMessage).includes(x(t));
64
76
  }
65
- function m(e) {
77
+ function d(e) {
66
78
  if (e && typeof e == "object") {
67
79
  const t = e;
68
80
  if (t.code === "23505")
@@ -72,72 +84,70 @@ function m(e) {
72
84
  }
73
85
  return e instanceof Error ? e.message : "Unknown error.";
74
86
  }
75
- async function O(e, t) {
87
+ async function A(e, t) {
76
88
  try {
77
89
  const s = l(t);
78
- g(t);
90
+ f(t);
79
91
  const [{ generateCortexWidgetDefinition: i }, { insertCortexWidgetDefinition: r }] = await Promise.all([
80
92
  import("./ai-cortex-widget-builder.es.js"),
81
93
  import("./cortex-widget-registry.es.js")
82
- ]), o = await i(x(e, t)), a = await r(s, o.definition);
83
- return p(a), {
84
- definition: f(a),
85
- editUrl: `/cms/custom-blocks/${a.id}/edit`,
94
+ ]), o = await i(C(e, t)), n = await r(s, o.definition);
95
+ return p(n), {
96
+ definition: g(n),
97
+ editUrl: `/cms/custom-blocks/${n.id}/edit`,
86
98
  mutationExecuted: !0,
87
99
  success: !0
88
100
  };
89
101
  } catch (s) {
90
- return { mutationExecuted: !1, message: m(s), success: !1 };
102
+ return { mutationExecuted: !1, message: d(s), success: !1 };
91
103
  }
92
104
  }
93
- async function A(e, t) {
105
+ async function $(e, t) {
94
106
  try {
95
107
  const s = l(t);
96
- g(t);
108
+ f(t);
97
109
  const { data: i } = await s.from("custom_block_definitions").select(h).eq("slug", e.slug).maybeSingle();
98
110
  if (!i)
99
111
  return { mutationExecuted: !1, message: `No custom block found with slug "${e.slug}".`, success: !1 };
100
112
  const [{ generateCortexWidgetDefinition: r }, { customBlockDefinitionCreateSchema: o }] = await Promise.all([
101
113
  import("./ai-cortex-widget-builder.es.js"),
102
114
  import("@nextblock-cms/utils/custom-blocks")
103
- ]), a = await r(
104
- x(
115
+ ]), n = await r(
116
+ C(
105
117
  {
106
- 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(
107
- { fields: i.fields, layout_schema: i.layout_schema, name: i.name }
108
- )}`,
118
+ context: O(i),
109
119
  prompt: e.prompt
110
120
  },
111
121
  t
112
122
  )
113
123
  ), c = o.parse({
114
- ...a.definition,
124
+ ...n.definition,
115
125
  is_original: i.is_original,
116
126
  slug: i.slug
117
- }), { data: d, error: b } = await s.from("custom_block_definitions").update({
127
+ }), { data: m, error: b } = await s.from("custom_block_definitions").update({
118
128
  description: c.description,
119
129
  fields: k(c.fields),
120
130
  layout_schema: k(c.layout_schema),
121
131
  name: c.name
122
132
  }).eq("id", i.id).select(h).single();
123
- return b || !d ? { mutationExecuted: !1, message: b?.message ?? "Failed to update custom block.", success: !1 } : (p(d), {
124
- definition: f(d),
133
+ return b || !m ? { mutationExecuted: !1, message: b?.message ?? "Failed to update custom block.", success: !1 } : (p(m), {
134
+ definition: g(m),
125
135
  editUrl: `/cms/custom-blocks/${i.id}/edit`,
126
136
  mutationExecuted: !0,
127
137
  success: !0
128
138
  });
129
139
  } catch (s) {
130
- return { mutationExecuted: !1, message: m(s), success: !1 };
140
+ return { mutationExecuted: !1, message: d(s), success: !1 };
131
141
  }
132
142
  }
133
143
  async function B(e, t) {
134
144
  try {
135
145
  const s = l(t);
136
- g(t);
146
+ f(t);
137
147
  const { data: i } = await s.from("custom_block_definitions").select("id, slug, name").eq("slug", e.slug).maybeSingle();
138
148
  if (!i)
139
149
  return { mutationExecuted: !1, message: `No custom block found with slug "${e.slug}".`, success: !1 };
140
- const r = E(i.slug);
150
+ const r = T(i.slug);
141
151
  if (!q(t, r))
142
152
  return {
143
153
  confirmationPhrase: r,
@@ -155,66 +165,66 @@ async function B(e, t) {
155
165
  success: !0
156
166
  });
157
167
  } catch (s) {
158
- return { mutationExecuted: !1, message: m(s), success: !1 };
168
+ return { mutationExecuted: !1, message: d(s), success: !1 };
159
169
  }
160
170
  }
161
- async function U(e, t) {
171
+ async function D(e, t) {
162
172
  try {
163
173
  const s = l(t), { data: i, error: r } = await s.from("custom_block_definitions").select("id, slug, name, description, fields, is_original").order("name", { ascending: !0 });
164
174
  if (r)
165
175
  return { message: r.message, success: !1 };
166
176
  let o = Array.isArray(i) ? i : [];
167
177
  if (e.query) {
168
- const a = e.query.toLowerCase();
178
+ const n = e.query.toLowerCase();
169
179
  o = o.filter(
170
- (c) => String(c.name || "").toLowerCase().includes(a) || String(c.slug || "").toLowerCase().includes(a)
180
+ (c) => String(c.name || "").toLowerCase().includes(n) || String(c.slug || "").toLowerCase().includes(n)
171
181
  );
172
182
  }
173
183
  return {
174
- blocks: o.map((a) => f(a)),
184
+ blocks: o.map((n) => g(n)),
175
185
  count: o.length,
176
186
  success: !0
177
187
  };
178
188
  } catch (s) {
179
- return { message: m(s), success: !1 };
189
+ return { message: d(s), success: !1 };
180
190
  }
181
191
  }
182
- function $(e) {
192
+ function N(e) {
183
193
  return {
184
194
  create_custom_block: u({
185
195
  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.',
186
- execute: (t) => O(t, e),
187
- inputSchema: C,
196
+ execute: (t) => A(t, e),
197
+ inputSchema: w,
188
198
  strict: !0
189
199
  }),
190
200
  delete_custom_block: u({
191
201
  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.",
192
202
  execute: (t) => B(t, e),
193
- inputSchema: _,
203
+ inputSchema: E,
194
204
  strict: !0
195
205
  }),
196
206
  list_custom_blocks: u({
197
207
  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.",
198
- execute: (t) => U(t, e),
208
+ execute: (t) => D(t, e),
199
209
  inputSchema: S,
200
210
  strict: !0
201
211
  }),
202
212
  update_custom_block: u({
203
213
  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.",
204
- execute: (t) => A(t, e),
205
- inputSchema: w,
214
+ execute: (t) => $(t, e),
215
+ inputSchema: _,
206
216
  strict: !0
207
217
  })
208
218
  };
209
219
  }
210
220
  export {
211
- $ as createCortexCustomBlockTools,
212
- C as createCustomBlockInputSchema,
213
- _ as deleteCustomBlockInputSchema,
214
- O as executeCreateCustomBlock,
221
+ N as createCortexCustomBlockTools,
222
+ w as createCustomBlockInputSchema,
223
+ E as deleteCustomBlockInputSchema,
224
+ A as executeCreateCustomBlock,
215
225
  B as executeDeleteCustomBlock,
216
- U as executeListCustomBlocks,
217
- A as executeUpdateCustomBlock,
226
+ D as executeListCustomBlocks,
227
+ $ as executeUpdateCustomBlock,
218
228
  S as listCustomBlocksInputSchema,
219
- w as updateCustomBlockInputSchema
229
+ _ as updateCustomBlockInputSchema
220
230
  };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const v=require("ai");require("./zod-config.cjs.js");const n=require("zod"),G=100,W=20,k=100,z=20,R="[REDACTED]",g="cortex_ai_openrouter_api_key",$={blocks:{columns:["id","page_id","post_id","language_id","block_type","content","order","created_at","updated_at"],description:"CMS page/post content blocks.",primaryKey:["id"]},coupon_freemius_mappings:{columns:["id","coupon_id","product_id","freemius_product_id","freemius_coupon_id","freemius_coupon_code","sync_status","sync_error","remote_payload","last_synced_at","created_at","updated_at"],description:"Freemius coupon sync mappings.",primaryKey:["id"]},coupon_products:{columns:["coupon_id","product_id","created_at"],description:"Coupon product allow-list rows.",primaryKey:["coupon_id","product_id"]},coupon_redemptions:{columns:["id","coupon_id","order_id","coupon_code","provider","discount_total","user_id","customer_email","metadata","redeemed_at"],description:"Coupon redemption records.",primaryKey:["id"]},coupons:{columns:["id","code","name","internal_note","provider_scope","discount_type","discount_amount","is_active","starts_at","ends_at","redemption_limit","redemptions_count","freemius_sync_status","freemius_sync_error","created_at","updated_at"],description:"Commerce coupons.",primaryKey:["id"]},cortex_ai_db_mutation_audit:{columns:["id","actor_user_id","tool_name","action_name","target_tables","operation_summary","payload_hash","payload","preview","status","error_message","created_at"],description:"Read-only Cortex AI database mutation audit trail.",primaryKey:["id"],readOnly:!0},currencies:{columns:["id","code","symbol","exchange_rate","is_default","is_active","rounding_mode","rounding_increment","rounding_charm_amount","auto_update_exchange_rate","exchange_rate_updated_at","exchange_rate_source","auto_sync_product_prices","created_at","updated_at"],description:"Storefront currencies and FX settings.",primaryKey:["id"]},freemius_plans:{columns:["id","product_id","name","title","created_at","updated_at"],description:"Freemius plan metadata.",primaryKey:["id"]},freemius_pricing:{columns:["id","plan_id","api_monthly_price","api_annual_price","api_lifetime_price","override_monthly_price","override_annual_price","override_lifetime_price","license_quota","is_active","created_at","updated_at"],description:"Freemius pricing metadata.",primaryKey:["id"]},inventory_items:{columns:["sku","quantity","created_at","updated_at"],description:"Source-of-truth inventory by SKU.",primaryKey:["sku"]},languages:{columns:["id","code","name","is_default","is_active","created_at","updated_at"],description:"CMS languages/locales.",primaryKey:["id"]},logos:{columns:["id","name","media_id","created_at"],description:"Brand logos.",primaryKey:["id"]},media:{columns:["id","uploader_id","file_name","object_key","file_type","size_bytes","description","width","height","blur_data_url","variants","file_path","folder","created_at","updated_at"],description:"Media metadata for uploaded assets.",primaryKey:["id"]},navigation_items:{columns:["id","language_id","menu_key","label","url","parent_id","order","page_id","translation_group_id","created_at","updated_at"],description:"CMS navigation tree items.",primaryKey:["id"]},order_items:{columns:["id","order_id","product_id","variant_id","quantity","price_at_purchase"],description:"Commerce order line items.",primaryKey:["id"]},orders:{columns:["id","user_id","status","total","stripe_session_id","payment_intent_id","customer_details","provider","freemius_product_id","freemius_plan_id","freemius_license_id","freemius_subscription_id","freemius_trial_id","freemius_user_id","freemius_trial_ends_at","freemius_last_event_type","freemius_last_synced_at","currency","subtotal","shipping_total","tax_total","tax_details","exchange_rate_at_purchase","inventory_deducted_at","invoice_number","paid_at","created_at","coupon_id","coupon_code","discount_total","discount_details"],description:"Commerce orders.",primaryKey:["id"]},package_activations:{columns:["id","license_key","instance_name","package_id","status","meta","last_validated_at","created_at"],description:"NextBlock package activations.",primaryKey:["id"]},page_revisions:{columns:["id","page_id","author_id","version","revision_type","content","created_at"],description:"Page revision history.",primaryKey:["id"],readOnly:!0},pages:{columns:["id","language_id","author_id","title","slug","status","meta_title","meta_description","feature_image_id","version","translation_group_id","created_at","updated_at"],description:"CMS pages.",primaryKey:["id"]},post_revisions:{columns:["id","post_id","author_id","version","revision_type","content","created_at"],description:"Post revision history.",primaryKey:["id"],readOnly:!0},product_revisions:{columns:["id","product_id","author_id","version","revision_type","content","created_at"],description:"Product revision history.",primaryKey:["id"],readOnly:!0},posts:{columns:["id","language_id","author_id","title","slug","label","excerpt","subtitle","status","published_at","meta_title","meta_description","feature_image_id","version","translation_group_id","created_at","updated_at"],description:"CMS posts/articles.",primaryKey:["id"]},product_attribute_terms:{columns:["id","attribute_id","value","slug","sort_order","value_translations","created_at","updated_at"],description:"Product attribute terms.",primaryKey:["id"]},product_attributes:{columns:["id","name","slug","name_translations","created_at","updated_at"],description:"Product attribute definitions.",primaryKey:["id"]},product_media:{columns:["product_id","media_id","sort_order"],description:"Product media join rows.",primaryKey:["product_id","media_id"]},product_variants:{columns:["id","product_id","sku","price_adjustment","price","prices","sale_price","sale_prices","stock_quantity","upc","main_media_id","created_at","updated_at"],description:"Sellable product variants.",primaryKey:["id"]},products:{columns:["id","language_id","translation_group_id","sku","title","slug","product_type","payment_provider","price","prices","sale_price","sale_prices","stock","status","meta_title","meta_description","short_description","description_json","metadata","freemius_plan_id","freemius_product_id","trial_period_days","trial_requires_payment_method","upc","is_taxable","created_at","updated_at"],description:"Product catalog records.",primaryKey:["id"]},profiles:{columns:["id","updated_at","full_name","avatar_url","website","phone","role"],description:"Read-only user profiles. Never mutate through Cortex AI.",primaryKey:["id"],readOnly:!0},shipping_zone_locations:{columns:["id","zone_id","country_code","state_code","postal_code","created_at"],description:"Shipping zone location match rules.",primaryKey:["id"]},shipping_zone_methods:{columns:["id","zone_id","method_type","cost_amount","cost_currency","min_order_amount","name","name_translations","currency_pricing_mode","cost_amounts","min_order_amounts","created_at","updated_at"],description:"Shipping methods/rates.",primaryKey:["id"]},shipping_zones:{columns:["id","name","priority_order","created_at","updated_at"],description:"Shipping zones.",primaryKey:["id"]},site_settings:{columns:["key","value"],description:"Global site settings. Cortex AI API-key setting row is protected.",primaryKey:["key"]},tax_rates:{columns:["id","country_code","state_code","tax_name","tax_rate","created_at","updated_at"],description:"Manual tax rates.",primaryKey:["id"]},translations:{columns:["key","translations","created_at","updated_at"],description:"Shared translation strings.",primaryKey:["key"]},user_addresses:{columns:["id","user_id","address_type","is_default","recipient_name","company_name","line1","line2","city","state","postal_code","country_code","created_at","updated_at"],description:"Read-only user addresses. Never mutate through Cortex AI.",primaryKey:["id"],readOnly:!0},variant_attribute_mapping:{columns:["variant_id","attribute_term_id"],description:"Variant to attribute-term join rows.",primaryKey:["variant_id","attribute_term_id"]}},Y=n.z.enum(["eq","neq","gt","gte","lt","lte","ilike","in","is"]),N=n.z.strictObject({column:n.z.string().trim().min(1).max(120),operator:Y.default("eq"),value:n.z.unknown()}),H=n.z.strictObject({ascending:n.z.boolean().default(!0),column:n.z.string().trim().min(1).max(120)}),j=n.z.strictObject({includeReadOnly:n.z.boolean().default(!0),table:n.z.string().trim().min(1).max(120).optional()}),T=n.z.strictObject({columns:n.z.array(n.z.string().trim().min(1).max(120)).min(1).max(40).optional(),filters:n.z.array(N).max(12).default([]),limit:n.z.number().int().min(1).max(G).default(W),offset:n.z.number().int().min(0).max(1e4).default(0),orderBy:H.optional(),table:n.z.string().trim().min(1).max(120)}),S=n.z.strictObject({filters:n.z.array(N).max(12).optional(),operation:n.z.enum(["delete","insert","update","upsert"]),rows:n.z.array(n.z.record(n.z.string(),n.z.unknown())).min(1).max(z).optional(),summary:n.z.string().trim().min(1).max(500).optional(),table:n.z.string().trim().min(1).max(120),values:n.z.record(n.z.string(),n.z.unknown()).optional()}),D=n.z.strictObject({actions:n.z.array(S).min(1).max(8),summary:n.z.string().trim().min(1).max(500).optional()});function E(e){if(!e?.supabase)throw new Error("Cortex AI database tools require a Supabase client.");return e.supabase}function f(e){return e?typeof e=="object"&&"message"in e?String(e.message||"Unknown database error."):String(e):"Unknown database error."}function K(e){return e===null||typeof e!="object"?JSON.stringify(e):Array.isArray(e)?`[${e.map(t=>K(t)).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${K(e[t])}`).join(",")}}`}function L(e){let t=2166136261;const r=K(e);for(let a=0;a<r.length;a++)t^=r.charCodeAt(a),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")}function I(e){return e.replace(/\s+/g," ").trim().toUpperCase()}function Z(e,t,r){return`${I(`CONFIRM ${e} ${t}`)} #${L(r)}`}function ee(e){return{confirmationPhrase:Z(e.action,e.subject,e.payload),mutationExecuted:!1,preview:e.preview,requiresConfirmation:!0,success:!0}}function q(e){if(e.context?.skipConfirmation)return null;const t=ee(e),r=I(e.context?.latestUserMessage||""),a=I(t.confirmationPhrase);return r&&!r.includes(a)?{...t,message:"The database target changed or the confirmation did not match. Please review and confirm again."}:r.includes(a)?null:t}function te(e){return Object.prototype.hasOwnProperty.call($,e)}function M(e){const t=e.trim();if(t.includes(".")||t.toLowerCase().startsWith("auth"))throw new Error("Cortex AI cannot access auth schema tables.");if(!te(t))throw new Error(`Table "${t}" is not available to Cortex AI database tools.`);return t}function _(e){return $[e]}function w(e){return/(?:password|token|secret|api[_-]?key|private[_-]?key|credential)/i.test(e)}function b(e,t){if(!_(e).columns.includes(t))throw new Error(`Column "${t}" is not available on table "${e}".`);if(w(t))throw new Error(`Column "${t}" is protected and cannot be used through Cortex AI.`)}function O(e,t="payload"){if(Array.isArray(e)){e.forEach((r,a)=>O(r,`${t}[${a}]`));return}if(!(!e||typeof e!="object"))for(const[r,a]of Object.entries(e)){if(w(r))throw new Error(`Protected field "${t}.${r}" cannot be written through Cortex AI.`);O(a,`${t}.${r}`)}}function h(e){if(Array.isArray(e))return e.map(r=>h(r));if(!e||typeof e!="object")return e;const t={};for(const[r,a]of Object.entries(e))t[r]=w(r)?R:h(a);return t}function re(e){return e.map(t=>t&&typeof t=="object"&&!Array.isArray(t)&&t.key===g?{key:g,value:R}:h(t))}function ae(e,t){if(e!=="site_settings")return;if(JSON.stringify(t).toLowerCase().includes(g))throw new Error("The Cortex AI OpenRouter API key site setting is protected.")}function ie(e,t){switch(t.operator){case"eq":return e.eq(t.column,t.value);case"neq":return e.neq(t.column,t.value);case"gt":return e.gt(t.column,t.value);case"gte":return e.gte(t.column,t.value);case"lt":return e.lt(t.column,t.value);case"lte":return e.lte(t.column,t.value);case"ilike":if(typeof t.value!="string")throw new Error(`Filter "${t.column}" with ilike requires a string value.`);return e.ilike(t.column,t.value);case"in":if(!Array.isArray(t.value))throw new Error(`Filter "${t.column}" with in requires an array value.`);return e.in(t.column,t.value);case"is":return e.is(t.column,t.value)}}function x(e,t,r){let a=t;for(const o of r)b(e,o.column),a=ie(a,o);return e==="site_settings"&&(a=a.neq("key",g)),a}function oe(e,t){const r=_(e),a=t?.length?t:r.columns.filter(o=>!w(o));return a.forEach(o=>b(e,o)),a.join(",")}function F(e,t){return t.map(r=>`${r}=${String(e[r]??"")}`).join("|")}async function U(e,t,r){const a=_(t);let o=e.from(t).select(a.primaryKey.join(",")).limit(k+1);o=x(t,o,r);const{data:i,error:s}=await o;if(s)throw new Error(`Failed to preview database mutation: ${f(s)}`);const d=Array.isArray(i)?i:[];if(d.length>k)throw new Error(`Refusing to mutate more than ${k} rows.`);return d}function B(e){const t=M(e.table),r=_(t),a=e.operation;if(r.readOnly)throw new Error(`Table "${t}" is read-only for Cortex AI.`);if(ae(t,e),(a==="update"||a==="delete")&&(!e.filters||e.filters.length===0))throw new Error(`${a} operations require at least one filter.`);if((a==="insert"||a==="upsert")&&(!e.rows||e.rows.length===0))throw new Error(`${a} operations require rows.`);if(a==="update"&&(!e.values||Object.keys(e.values).length===0))throw new Error("update operations require values.");if(e.rows&&e.rows.length>z)throw new Error(`Refusing to mutate more than ${z} input rows.`);const o=e.rows??(e.values?[e.values]:[]);for(const i of o){O(i);for(const s of Object.keys(i))b(t,s)}for(const i of e.filters??[])b(t,i.column);return t}function X(e){const{input:t,table:r,targetRows:a}=e,o=_(r),i=a.map(m=>F(m,o.primaryKey)).sort(),s=t.rows?.length??0,d=t.operation==="insert"||t.operation==="upsert"?s:a.length,l=t.summary||`${t.operation} ${d} ${d===1?"row":"rows"} in ${r}.`;return{affectedCount:d,operation:t.operation,sampleTargetIds:i.slice(0,10),summary:l,table:r,targetIds:i}}async function A(e){const t=e.context?.actorUserId;if(!t)return{auditError:"Missing actor user id.",auditLogged:!1};try{const{error:r}=await E(e.context).from("cortex_ai_db_mutation_audit").insert({action_name:e.toolName,actor_user_id:t,error_message:e.errorMessage??null,operation_summary:e.summary,payload:h(e.input),payload_hash:L(e.input),preview:h(e.preview),status:e.status,target_tables:e.targetTables,tool_name:e.toolName});return r?{auditError:f(r),auditLogged:!1}:{auditLogged:!0}}catch(r){return{auditError:f(r),auditLogged:!1}}}async function ne(e,t,r){const o=_(t).primaryKey.join(",");let i;e.operation==="insert"?i=r.from(t).insert(e.rows).select(o):e.operation==="upsert"?i=r.from(t).upsert(e.rows).select(o):e.operation==="update"?(i=r.from(t).update(e.values),i=x(t,i,e.filters??[]),i=i.select(o)):(i=r.from(t).delete(),i=x(t,i,e.filters??[]),i=i.select(o));const{data:s,error:d}=await i;if(d)throw new Error(f(d));return Array.isArray(s)?s:[]}async function V(e){const t=j.parse(e),a=(t.table?[M(t.table)]:Object.keys($)).filter(o=>t.includeReadOnly||!_(o).readOnly).map(o=>{const i=_(o);return{columns:i.columns.filter(s=>!w(s)),description:i.description,primaryKey:i.primaryKey,readOnly:!!i.readOnly,table:o}});return{safetyNotes:["Use read_database_records for reads and execute_database_mutation/action_plan for writes.","No auth schema access, no arbitrary SQL, no password/secret/API-key fields.","profiles, user_addresses, and cortex_ai_db_mutation_audit are read-only.",`site_settings.${g} is protected.`],success:!0,tables:a}}async function J(e,t){const r=T.parse(e),a=M(r.table),o=oe(a,r.columns);let i=E(t).from(a).select(o).range(r.offset,r.offset+r.limit-1);i=x(a,i,r.filters),r.orderBy&&(b(a,r.orderBy.column),i=i.order(r.orderBy.column,{ascending:r.orderBy.ascending}));const{data:s,error:d}=await i;if(d)throw new Error(`Failed to read database records: ${f(d)}`);const l=Array.isArray(s)?s:[];return{columns:o.split(","),limit:r.limit,offset:r.offset,rows:re(l),success:!0,table:a}}async function P(e,t){const r=S.parse(e),a=B(r),o=E(t),i=r.operation==="update"||r.operation==="delete"?await U(o,a,r.filters??[]):[],s=X({input:r,table:a,targetRows:i}),d={input:r,targetIds:s.targetIds},l=q({action:`DATABASE ${r.operation}`,context:t,payload:d,preview:s,subject:a});if(l)return l;try{const m=await ne(r,a,o),p=t?.skipAudit?{auditLogged:!1}:await A({context:t,input:d,preview:s,status:"success",summary:String(s.summary),targetTables:[a],toolName:"execute_database_mutation"});return{affectedCount:m.length||s.affectedCount,auditLogged:p.auditLogged,...p.auditError?{auditError:p.auditError}:{},mutationExecuted:!0,operation:r.operation,sampleTargetIds:m.map(c=>F(c,_(a).primaryKey)).slice(0,10),success:!0,summary:s.summary,table:a}}catch(m){const p=f(m),c=t?.skipAudit?{auditLogged:!1}:await A({context:t,errorMessage:p,input:d,preview:s,status:"failure",summary:String(s.summary),targetTables:[a],toolName:"execute_database_mutation"});return{auditLogged:c.auditLogged,...c.auditError?{auditError:c.auditError}:{},message:`Database mutation failed: ${p}`,mutationExecuted:!1,operation:r.operation,success:!1,table:a}}}async function Q(e,t){const r=D.parse(e),a=[];for(const c of r.actions){const y=B(c),u=c.operation==="update"||c.operation==="delete"?await U(E(t),y,c.filters??[]):[];a.push({input:c,preview:X({input:c,table:y,targetRows:u}),table:y})}const o=a.map(({preview:c})=>String(c.summary)),i={actionCount:a.length,actionSummaries:o,summary:r.summary||`Run ${a.length} confirmed database actions.`,tables:Array.from(new Set(a.map(c=>c.table)))},s=a.map(({input:c,preview:y,table:u})=>({input:c,table:u,targetIds:y.targetIds})),d=q({action:"DATABASE ACTION PLAN",context:t,payload:s,preview:i,subject:`${a.length} actions`});if(d)return d;const l=[];let m=!1;for(const[c,y]of a.entries()){const u=await P(y.input,{...t,skipAudit:!0,skipConfirmation:!0});if(l.push(u),u&&typeof u=="object"&&u.mutationExecuted===!0&&(m=!0),!u||typeof u!="object"||u.success===!1){const C=await A({context:t,errorMessage:u&&typeof u=="object"&&typeof u.message=="string"?u.message:`Database action ${c+1} failed.`,input:s,preview:i,status:"failure",summary:String(i.summary),targetTables:i.tables,toolName:"execute_database_action_plan"});return{actionCount:a.length,auditLogged:C.auditLogged,...C.auditError?{auditError:C.auditError}:{},failedActionIndex:c,message:u&&typeof u=="object"&&typeof u.message=="string"?u.message:`Database action ${c+1} failed.`,mutationExecuted:m,results:l,success:!1}}}const p=await A({context:t,input:s,preview:i,status:"success",summary:String(i.summary),targetTables:i.tables,toolName:"execute_database_action_plan"});return{actionCount:a.length,auditLogged:p.auditLogged,...p.auditError?{auditError:p.auditError}:{},mutationExecuted:m,results:l,success:!0,summary:r.summary??null}}function se(e){return{describe_database_schema:v.tool({description:"Describe the public database tables Cortex AI can read or mutate, including read-only tables, primary keys, and writable columns. Use before broad database tasks when unsure about schema.",execute:t=>V(t),inputSchema:j,strict:!0}),execute_database_action_plan:v.tool({description:"Execute up to 8 typed database mutations as one confirmed plan. Mutating: first returns one combined confirmation preview and Confirm button; after confirmation, runs each action in order and stops on the first failure.",execute:t=>Q(t,e),inputSchema:D,strict:!0}),execute_database_mutation:v.tool({description:"Run one typed insert, update, upsert, or delete against an allowed public database table. Mutating: always previews affected rows and requires exact user confirmation before execution. Does not support arbitrary SQL.",execute:t=>P(t,e),inputSchema:S,strict:!0}),read_database_records:v.tool({description:"Read records from an allowed public database table with validated columns, filters, ordering, limit, and offset. Read-only and redacts protected secret-like values.",execute:t=>J(t,e),inputSchema:T,strict:!0})}}exports.createCortexDatabaseAgentTools=se;exports.describeDatabaseSchemaInputSchema=j;exports.executeDatabaseActionPlan=Q;exports.executeDatabaseActionPlanInputSchema=D;exports.executeDatabaseMutation=P;exports.executeDatabaseMutationInputSchema=S;exports.executeDescribeDatabaseSchema=V;exports.executeReadDatabaseRecords=J;exports.readDatabaseRecordsInputSchema=T;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const w=require("ai");require("./zod-config.cjs.js");const n=require("zod"),W=100,Y=20,k=100,C=20,R="[REDACTED]",N="cortex_ai_openrouter_api_key",T=new Set([N,"bot_protection_secret","cortex_ai_pexels_api_key","cortex_ai_unsplash_access_key","email_secret","payment_secret"]),$={blocks:{columns:["id","page_id","post_id","language_id","block_type","content","order","created_at","updated_at"],description:"CMS page/post content blocks.",primaryKey:["id"]},coupon_freemius_mappings:{columns:["id","coupon_id","product_id","freemius_product_id","freemius_coupon_id","freemius_coupon_code","sync_status","sync_error","remote_payload","last_synced_at","created_at","updated_at"],description:"Freemius coupon sync mappings.",primaryKey:["id"]},coupon_products:{columns:["coupon_id","product_id","created_at"],description:"Coupon product allow-list rows.",primaryKey:["coupon_id","product_id"]},coupon_redemptions:{columns:["id","coupon_id","order_id","coupon_code","provider","discount_total","user_id","customer_email","metadata","redeemed_at"],description:"Coupon redemption records.",primaryKey:["id"]},coupons:{columns:["id","code","name","internal_note","provider_scope","discount_type","discount_amount","is_active","starts_at","ends_at","redemption_limit","redemptions_count","freemius_sync_status","freemius_sync_error","created_at","updated_at"],description:"Commerce coupons.",primaryKey:["id"]},cortex_ai_db_mutation_audit:{columns:["id","actor_user_id","tool_name","action_name","target_tables","operation_summary","payload_hash","payload","preview","status","error_message","created_at"],description:"Read-only Cortex AI database mutation audit trail.",primaryKey:["id"],readOnly:!0},currencies:{columns:["id","code","symbol","exchange_rate","is_default","is_active","rounding_mode","rounding_increment","rounding_charm_amount","auto_update_exchange_rate","exchange_rate_updated_at","exchange_rate_source","auto_sync_product_prices","created_at","updated_at"],description:"Storefront currencies and FX settings.",primaryKey:["id"]},freemius_plans:{columns:["id","product_id","name","title","created_at","updated_at"],description:"Freemius plan metadata.",primaryKey:["id"]},freemius_pricing:{columns:["id","plan_id","api_monthly_price","api_annual_price","api_lifetime_price","override_monthly_price","override_annual_price","override_lifetime_price","license_quota","is_active","created_at","updated_at"],description:"Freemius pricing metadata.",primaryKey:["id"]},inventory_items:{columns:["sku","quantity","created_at","updated_at"],description:"Source-of-truth inventory by SKU.",primaryKey:["sku"]},languages:{columns:["id","code","name","is_default","is_active","created_at","updated_at"],description:"CMS languages/locales.",primaryKey:["id"]},logos:{columns:["id","name","media_id","created_at"],description:"Brand logos.",primaryKey:["id"]},media:{columns:["id","uploader_id","file_name","object_key","file_type","size_bytes","description","width","height","blur_data_url","variants","file_path","folder","created_at","updated_at"],description:"Media metadata for uploaded assets.",primaryKey:["id"]},navigation_items:{columns:["id","language_id","menu_key","label","url","parent_id","order","page_id","translation_group_id","created_at","updated_at"],description:"CMS navigation tree items.",primaryKey:["id"]},order_items:{columns:["id","order_id","product_id","variant_id","quantity","price_at_purchase"],description:"Commerce order line items.",primaryKey:["id"]},orders:{columns:["id","user_id","status","total","stripe_session_id","payment_intent_id","customer_details","provider","freemius_product_id","freemius_plan_id","freemius_license_id","freemius_subscription_id","freemius_trial_id","freemius_user_id","freemius_trial_ends_at","freemius_last_event_type","freemius_last_synced_at","currency","subtotal","shipping_total","tax_total","tax_details","exchange_rate_at_purchase","inventory_deducted_at","invoice_number","paid_at","created_at","coupon_id","coupon_code","discount_total","discount_details"],description:"Commerce orders.",primaryKey:["id"]},package_activations:{columns:["id","license_key","instance_name","package_id","status","meta","last_validated_at","created_at"],description:"NextBlock package activations.",primaryKey:["id"]},page_revisions:{columns:["id","page_id","author_id","version","revision_type","content","created_at"],description:"Page revision history.",primaryKey:["id"],readOnly:!0},pages:{columns:["id","language_id","author_id","title","slug","status","meta_title","meta_description","feature_image_id","version","translation_group_id","created_at","updated_at"],description:"CMS pages.",primaryKey:["id"]},post_revisions:{columns:["id","post_id","author_id","version","revision_type","content","created_at"],description:"Post revision history.",primaryKey:["id"],readOnly:!0},product_revisions:{columns:["id","product_id","author_id","version","revision_type","content","created_at"],description:"Product revision history.",primaryKey:["id"],readOnly:!0},posts:{columns:["id","language_id","author_id","title","slug","label","excerpt","subtitle","status","published_at","meta_title","meta_description","feature_image_id","version","translation_group_id","created_at","updated_at"],description:"CMS posts/articles.",primaryKey:["id"]},product_attribute_terms:{columns:["id","attribute_id","value","slug","sort_order","value_translations","created_at","updated_at"],description:"Product attribute terms.",primaryKey:["id"]},product_attributes:{columns:["id","name","slug","name_translations","created_at","updated_at"],description:"Product attribute definitions.",primaryKey:["id"]},product_media:{columns:["product_id","media_id","sort_order"],description:"Product media join rows.",primaryKey:["product_id","media_id"]},product_variants:{columns:["id","product_id","sku","price_adjustment","price","prices","sale_price","sale_prices","stock_quantity","upc","main_media_id","created_at","updated_at"],description:"Sellable product variants.",primaryKey:["id"]},products:{columns:["id","language_id","translation_group_id","sku","title","slug","product_type","payment_provider","price","prices","sale_price","sale_prices","stock","status","meta_title","meta_description","short_description","description_json","metadata","freemius_plan_id","freemius_product_id","trial_period_days","trial_requires_payment_method","upc","is_taxable","created_at","updated_at"],description:"Product catalog records.",primaryKey:["id"]},profiles:{columns:["id","updated_at","full_name","avatar_url","website","phone","role"],description:"Read-only user profiles. Never mutate through Cortex AI.",primaryKey:["id"],readOnly:!0},shipping_zone_locations:{columns:["id","zone_id","country_code","state_code","postal_code","created_at"],description:"Shipping zone location match rules.",primaryKey:["id"]},shipping_zone_methods:{columns:["id","zone_id","method_type","cost_amount","cost_currency","min_order_amount","name","name_translations","currency_pricing_mode","cost_amounts","min_order_amounts","created_at","updated_at"],description:"Shipping methods/rates.",primaryKey:["id"]},shipping_zones:{columns:["id","name","priority_order","created_at","updated_at"],description:"Shipping zones.",primaryKey:["id"]},site_settings:{columns:["key","value"],description:"Global site settings. Cortex AI API-key setting row is protected.",primaryKey:["key"]},tax_rates:{columns:["id","country_code","state_code","tax_name","tax_rate","created_at","updated_at"],description:"Manual tax rates.",primaryKey:["id"]},translations:{columns:["key","translations","created_at","updated_at"],description:"Shared translation strings.",primaryKey:["key"]},user_addresses:{columns:["id","user_id","address_type","is_default","recipient_name","company_name","line1","line2","city","state","postal_code","country_code","created_at","updated_at"],description:"Read-only user addresses. Never mutate through Cortex AI.",primaryKey:["id"],readOnly:!0},variant_attribute_mapping:{columns:["variant_id","attribute_term_id"],description:"Variant to attribute-term join rows.",primaryKey:["variant_id","attribute_term_id"]}},H=n.z.enum(["eq","neq","gt","gte","lt","lte","ilike","in","is"]),L=n.z.strictObject({column:n.z.string().trim().min(1).max(120),operator:H.default("eq"),value:n.z.unknown()}),Z=n.z.strictObject({ascending:n.z.boolean().default(!0),column:n.z.string().trim().min(1).max(120)}),O=n.z.strictObject({includeReadOnly:n.z.boolean().default(!0),table:n.z.string().trim().min(1).max(120).optional()}),j=n.z.strictObject({columns:n.z.array(n.z.string().trim().min(1).max(120)).min(1).max(40).optional(),filters:n.z.array(L).max(12).default([]),limit:n.z.number().int().min(1).max(W).default(Y),offset:n.z.number().int().min(0).max(1e4).default(0),orderBy:Z.optional(),table:n.z.string().trim().min(1).max(120)}),S=n.z.strictObject({filters:n.z.array(L).max(12).optional(),operation:n.z.enum(["delete","insert","update","upsert"]),rows:n.z.array(n.z.record(n.z.string(),n.z.unknown())).min(1).max(C).optional(),summary:n.z.string().trim().min(1).max(500).optional(),table:n.z.string().trim().min(1).max(120),values:n.z.record(n.z.string(),n.z.unknown()).optional()}),D=n.z.strictObject({actions:n.z.array(S).min(1).max(8),summary:n.z.string().trim().min(1).max(500).optional()});function A(e){if(!e?.supabase)throw new Error("Cortex AI database tools require a Supabase client.");return e.supabase}function f(e){return e?typeof e=="object"&&"message"in e?String(e.message||"Unknown database error."):String(e):"Unknown database error."}function K(e){return e===null||typeof e!="object"?JSON.stringify(e):Array.isArray(e)?`[${e.map(t=>K(t)).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${K(e[t])}`).join(",")}}`}function q(e){let t=2166136261;const r=K(e);for(let a=0;a<r.length;a++)t^=r.charCodeAt(a),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")}function z(e){return e.replace(/\s+/g," ").trim().toUpperCase()}function ee(e,t,r){return`${z(`CONFIRM ${e} ${t}`)} #${q(r)}`}function te(e){return{confirmationPhrase:ee(e.action,e.subject,e.payload),mutationExecuted:!1,preview:e.preview,requiresConfirmation:!0,success:!0}}function F(e){if(e.context?.skipConfirmation)return null;const t=te(e),r=z(e.context?.latestUserMessage||""),a=z(t.confirmationPhrase);return r&&!r.includes(a)?{...t,message:"The database target changed or the confirmation did not match. Please review and confirm again."}:r.includes(a)?null:t}function re(e){return Object.prototype.hasOwnProperty.call($,e)}function P(e){const t=e.trim();if(t.includes(".")||t.toLowerCase().startsWith("auth"))throw new Error("Cortex AI cannot access auth schema tables.");if(!re(t))throw new Error(`Table "${t}" is not available to Cortex AI database tools.`);return t}function _(e){return $[e]}function h(e){return/(?:password|token|secret|api[_-]?key|private[_-]?key|credential)/i.test(e)}function g(e,t){if(!_(e).columns.includes(t))throw new Error(`Column "${t}" is not available on table "${e}".`);if(h(t))throw new Error(`Column "${t}" is protected and cannot be used through Cortex AI.`)}function I(e,t="payload"){if(Array.isArray(e)){e.forEach((r,a)=>I(r,`${t}[${a}]`));return}if(!(!e||typeof e!="object"))for(const[r,a]of Object.entries(e)){if(h(r))throw new Error(`Protected field "${t}.${r}" cannot be written through Cortex AI.`);I(a,`${t}.${r}`)}}function b(e){if(Array.isArray(e))return e.map(r=>b(r));if(!e||typeof e!="object")return e;const t={};for(const[r,a]of Object.entries(e))t[r]=h(r)?R:b(a);return t}function ae(e){return e.map(t=>{if(t&&typeof t=="object"&&!Array.isArray(t)){const r=t.key;if(typeof r=="string"&&T.has(r))return{key:r,value:R}}return b(t)})}function ie(e,t){if(e!=="site_settings")return;const r=JSON.stringify(t).toLowerCase();for(const a of T)if(r.includes(a))throw new Error(`The "${a}" site setting is protected.`)}function oe(e,t){switch(t.operator){case"eq":return e.eq(t.column,t.value);case"neq":return e.neq(t.column,t.value);case"gt":return e.gt(t.column,t.value);case"gte":return e.gte(t.column,t.value);case"lt":return e.lt(t.column,t.value);case"lte":return e.lte(t.column,t.value);case"ilike":if(typeof t.value!="string")throw new Error(`Filter "${t.column}" with ilike requires a string value.`);return e.ilike(t.column,t.value);case"in":if(!Array.isArray(t.value))throw new Error(`Filter "${t.column}" with in requires an array value.`);return e.in(t.column,t.value);case"is":return e.is(t.column,t.value)}}function v(e,t,r){let a=t;for(const o of r)g(e,o.column),a=oe(a,o);return e==="site_settings"&&(a=a.neq("key",N)),a}function ne(e,t){const r=_(e),a=t?.length?t:r.columns.filter(o=>!h(o));return a.forEach(o=>g(e,o)),a.join(",")}function U(e,t){return t.map(r=>`${r}=${String(e[r]??"")}`).join("|")}async function B(e,t,r){const a=_(t);let o=e.from(t).select(a.primaryKey.join(",")).limit(k+1);o=v(t,o,r);const{data:i,error:s}=await o;if(s)throw new Error(`Failed to preview database mutation: ${f(s)}`);const d=Array.isArray(i)?i:[];if(d.length>k)throw new Error(`Refusing to mutate more than ${k} rows.`);return d}function X(e){const t=P(e.table),r=_(t),a=e.operation;if(r.readOnly)throw new Error(`Table "${t}" is read-only for Cortex AI.`);if(ie(t,e),(a==="update"||a==="delete")&&(!e.filters||e.filters.length===0))throw new Error(`${a} operations require at least one filter.`);if((a==="insert"||a==="upsert")&&(!e.rows||e.rows.length===0))throw new Error(`${a} operations require rows.`);if(a==="update"&&(!e.values||Object.keys(e.values).length===0))throw new Error("update operations require values.");if(e.rows&&e.rows.length>C)throw new Error(`Refusing to mutate more than ${C} input rows.`);const o=e.rows??(e.values?[e.values]:[]);for(const i of o){I(i);for(const s of Object.keys(i))g(t,s)}for(const i of e.filters??[])g(t,i.column);return t}function V(e){const{input:t,table:r,targetRows:a}=e,o=_(r),i=a.map(p=>U(p,o.primaryKey)).sort(),s=t.rows?.length??0,d=t.operation==="insert"||t.operation==="upsert"?s:a.length,l=t.summary||`${t.operation} ${d} ${d===1?"row":"rows"} in ${r}.`;return{affectedCount:d,operation:t.operation,sampleTargetIds:i.slice(0,10),summary:l,table:r,targetIds:i}}async function x(e){const t=e.context?.actorUserId;if(!t)return{auditError:"Missing actor user id.",auditLogged:!1};try{const{error:r}=await A(e.context).from("cortex_ai_db_mutation_audit").insert({action_name:e.toolName,actor_user_id:t,error_message:e.errorMessage??null,operation_summary:e.summary,payload:b(e.input),payload_hash:q(e.input),preview:b(e.preview),status:e.status,target_tables:e.targetTables,tool_name:e.toolName});return r?{auditError:f(r),auditLogged:!1}:{auditLogged:!0}}catch(r){return{auditError:f(r),auditLogged:!1}}}async function se(e,t,r){const o=_(t).primaryKey.join(",");let i;e.operation==="insert"?i=r.from(t).insert(e.rows).select(o):e.operation==="upsert"?i=r.from(t).upsert(e.rows).select(o):e.operation==="update"?(i=r.from(t).update(e.values),i=v(t,i,e.filters??[]),i=i.select(o)):(i=r.from(t).delete(),i=v(t,i,e.filters??[]),i=i.select(o));const{data:s,error:d}=await i;if(d)throw new Error(f(d));return Array.isArray(s)?s:[]}async function G(e){const t=O.parse(e),a=(t.table?[P(t.table)]:Object.keys($)).filter(o=>t.includeReadOnly||!_(o).readOnly).map(o=>{const i=_(o);return{columns:i.columns.filter(s=>!h(s)),description:i.description,primaryKey:i.primaryKey,readOnly:!!i.readOnly,table:o}});return{safetyNotes:["Use read_database_records for reads and execute_database_mutation/action_plan for writes.","No auth schema access, no arbitrary SQL, no password/secret/API-key fields.","profiles, user_addresses, and cortex_ai_db_mutation_audit are read-only.",`Protected site_settings keys (never readable or writable): ${[...T].sort().join(", ")}.`],success:!0,tables:a}}async function J(e,t){const r=j.parse(e),a=P(r.table),o=ne(a,r.columns);let i=A(t).from(a).select(o).range(r.offset,r.offset+r.limit-1);i=v(a,i,r.filters),r.orderBy&&(g(a,r.orderBy.column),i=i.order(r.orderBy.column,{ascending:r.orderBy.ascending}));const{data:s,error:d}=await i;if(d)throw new Error(`Failed to read database records: ${f(d)}`);const l=Array.isArray(s)?s:[];return{columns:o.split(","),limit:r.limit,offset:r.offset,rows:ae(l),success:!0,table:a}}async function M(e,t){const r=S.parse(e),a=X(r),o=A(t),i=r.operation==="update"||r.operation==="delete"?await B(o,a,r.filters??[]):[],s=V({input:r,table:a,targetRows:i}),d={input:r,targetIds:s.targetIds},l=F({action:`DATABASE ${r.operation}`,context:t,payload:d,preview:s,subject:a});if(l)return l;try{const p=await se(r,a,o),m=t?.skipAudit?{auditLogged:!1}:await x({context:t,input:d,preview:s,status:"success",summary:String(s.summary),targetTables:[a],toolName:"execute_database_mutation"});return{affectedCount:p.length||s.affectedCount,auditLogged:m.auditLogged,...m.auditError?{auditError:m.auditError}:{},mutationExecuted:!0,operation:r.operation,sampleTargetIds:p.map(c=>U(c,_(a).primaryKey)).slice(0,10),success:!0,summary:s.summary,table:a}}catch(p){const m=f(p),c=t?.skipAudit?{auditLogged:!1}:await x({context:t,errorMessage:m,input:d,preview:s,status:"failure",summary:String(s.summary),targetTables:[a],toolName:"execute_database_mutation"});return{auditLogged:c.auditLogged,...c.auditError?{auditError:c.auditError}:{},message:`Database mutation failed: ${m}`,mutationExecuted:!1,operation:r.operation,success:!1,table:a}}}async function Q(e,t){const r=D.parse(e),a=[];for(const c of r.actions){const y=X(c),u=c.operation==="update"||c.operation==="delete"?await B(A(t),y,c.filters??[]):[];a.push({input:c,preview:V({input:c,table:y,targetRows:u}),table:y})}const o=a.map(({preview:c})=>String(c.summary)),i={actionCount:a.length,actionSummaries:o,summary:r.summary||`Run ${a.length} confirmed database actions.`,tables:Array.from(new Set(a.map(c=>c.table)))},s=a.map(({input:c,preview:y,table:u})=>({input:c,table:u,targetIds:y.targetIds})),d=F({action:"DATABASE ACTION PLAN",context:t,payload:s,preview:i,subject:`${a.length} actions`});if(d)return d;const l=[];let p=!1;for(const[c,y]of a.entries()){const u=await M(y.input,{...t,skipAudit:!0,skipConfirmation:!0});if(l.push(u),u&&typeof u=="object"&&u.mutationExecuted===!0&&(p=!0),!u||typeof u!="object"||u.success===!1){const E=await x({context:t,errorMessage:u&&typeof u=="object"&&typeof u.message=="string"?u.message:`Database action ${c+1} failed.`,input:s,preview:i,status:"failure",summary:String(i.summary),targetTables:i.tables,toolName:"execute_database_action_plan"});return{actionCount:a.length,auditLogged:E.auditLogged,...E.auditError?{auditError:E.auditError}:{},failedActionIndex:c,message:u&&typeof u=="object"&&typeof u.message=="string"?u.message:`Database action ${c+1} failed.`,mutationExecuted:p,results:l,success:!1}}}const m=await x({context:t,input:s,preview:i,status:"success",summary:String(i.summary),targetTables:i.tables,toolName:"execute_database_action_plan"});return{actionCount:a.length,auditLogged:m.auditLogged,...m.auditError?{auditError:m.auditError}:{},mutationExecuted:p,results:l,success:!0,summary:r.summary??null}}function ce(e){return{describe_database_schema:w.tool({description:"Describe the public database tables Cortex AI can read or mutate, including read-only tables, primary keys, and writable columns. Use before broad database tasks when unsure about schema.",execute:t=>G(t),inputSchema:O,strict:!0}),execute_database_action_plan:w.tool({description:"Execute up to 8 typed database mutations as one confirmed plan. Mutating: first returns one combined confirmation preview and Confirm button; after confirmation, runs each action in order and stops on the first failure.",execute:t=>Q(t,e),inputSchema:D,strict:!0}),execute_database_mutation:w.tool({description:"Run one typed insert, update, upsert, or delete against an allowed public database table. Mutating: always previews affected rows and requires exact user confirmation before execution. Does not support arbitrary SQL.",execute:t=>M(t,e),inputSchema:S,strict:!0}),read_database_records:w.tool({description:"Read records from an allowed public database table with validated columns, filters, ordering, limit, and offset. Read-only and redacts protected secret-like values.",execute:t=>J(t,e),inputSchema:j,strict:!0})}}exports.createCortexDatabaseAgentTools=ce;exports.describeDatabaseSchemaInputSchema=O;exports.executeDatabaseActionPlan=Q;exports.executeDatabaseActionPlanInputSchema=D;exports.executeDatabaseMutation=M;exports.executeDatabaseMutationInputSchema=S;exports.executeDescribeDatabaseSchema=G;exports.executeReadDatabaseRecords=J;exports.readDatabaseRecordsInputSchema=j;