@nextblock-cms/cortex 0.17.7 → 0.17.8

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.
@@ -1 +1 @@
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;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const k=require("ai"),x=require("./block-content-schemas.cjs.js"),te=require("./site-brief.cjs.js");require("./zod-config.cjs.js");const o=require("zod"),re=100,ae=20,S=100,$=20,B="[REDACTED]",F="cortex_ai_openrouter_api_key",j=new Set([F,"bot_protection_secret","cortex_ai_pexels_api_key","cortex_ai_unsplash_access_key","email_secret","payment_secret"]),O=new Set(["cortex_ai_build_session","is_admin_created","migration_baseline_generation","security_settings"]),ie={active_logo_id:o.z.string().uuid().nullable(),cortex_ai_site_brief:te.cortexSiteBriefSchema,footer_copyright:o.z.record(o.z.string().trim().min(2).max(12),o.z.string().max(500)),footer_show_attribution:o.z.boolean(),global_css:o.z.string().max(2e5),onboarding_state:o.z.record(o.z.string(),o.z.unknown()),site_description:o.z.string().max(1e3),site_keywords:o.z.string().max(1e3),site_title:o.z.string().max(200)};function oe(e){return e.map(t=>{const r=t.path.map(String).join(".");return r?`${r}: ${t.message}`:t.message}).join("; ")}function T(e,t){if(O.has(e))throw new Error(`The "${e}" site setting cannot be written through Cortex AI database tools.`);const r=ie[e];if(!r)return;const a=r.safeParse(t);if(!a.success)throw new Error(`Invalid value for site setting "${e}": ${oe(a.error.issues)}`)}async function L(e){const t=typeof e.blockType=="string"?e.blockType:"";if(!t)throw new Error(`${e.label}: block_type is required.`);if(!e.content||typeof e.content!="object"||Array.isArray(e.content))throw new Error(`${e.label}: content must be a JSON object.`);const r=e.content;if(x.isValidBlockType(t)){const i=x.validateCortexBlockContent(t,r,e.context);if(!i.isValid)throw new Error(`${e.label}: content is invalid for block type "${t}": ${i.errors.join("; ")}`);return}const a=(await e.definitions()).find(i=>i.slug===t);if(!a)throw new Error(`${e.label}: "${t}" is neither a built-in block type nor a custom block slug. Use list_custom_blocks to see the custom block definitions.`);const n=x.validateCustomBlockInstanceContent(a,r);if(!n.isValid)throw new Error(`${e.label}: content is invalid for custom block "${t}": ${n.errors.join("; ")}`)}async function U(e,t,r){if(t==="site_settings"){for(const i of e.rows??[])typeof i.key=="string"&&T(i.key,i.value);if(e.operation==="update"&&e.values){const i=typeof e.values.key=="string"?e.values.key:null,s=(e.filters??[]).find(u=>u.column==="key"&&u.operator==="eq"&&typeof u.value=="string"),c=i??(s?String(s.value):null);c&&("value"in e.values?T(c,e.values.value):O.has(c)&&T(c,void 0))}return}if(t!=="blocks")return;let a=null;const n=()=>a??=x.loadCustomBlockDefinitions(g(r));if(e.operation==="insert"||e.operation==="upsert"){for(const[i,s]of(e.rows??[]).entries())await L({blockType:s.block_type,content:s.content??{},context:r,definitions:n,label:`rows[${i}]`});return}if(e.operation==="update"&&e.values){const i="content"in e.values,s="block_type"in e.values;if(!i&&!s)return;if(s&&!i)throw new Error("Changing block_type requires the new content for that type in the same update.");const c=new Set;if(s)c.add(String(e.values.block_type));else{let u=g(r).from("blocks").select("id, block_type").limit(S+1);u=w(t,u,e.filters??[]);const{data:_,error:m}=await u;if(m)throw new Error(`Failed to read the blocks to update: ${f(m)}`);for(const d of Array.isArray(_)?_:[])c.add(String(d.block_type??""))}for(const u of c)await L({blockType:u,content:e.values.content,context:r,definitions:n,label:`values (block_type "${u}")`})}}const D={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"]}},ne=o.z.enum(["eq","neq","gt","gte","lt","lte","ilike","in","is"]),V=o.z.strictObject({column:o.z.string().trim().min(1).max(120),operator:ne.default("eq"),value:o.z.unknown()}),se=o.z.strictObject({ascending:o.z.boolean().default(!0),column:o.z.string().trim().min(1).max(120)}),P=o.z.strictObject({includeReadOnly:o.z.boolean().default(!0),table:o.z.string().trim().min(1).max(120).optional()}),M=o.z.strictObject({columns:o.z.array(o.z.string().trim().min(1).max(120)).min(1).max(40).optional(),filters:o.z.array(V).max(12).default([]),limit:o.z.number().int().min(1).max(re).default(ae),offset:o.z.number().int().min(0).max(1e4).default(0),orderBy:se.optional(),table:o.z.string().trim().min(1).max(120)}),A=o.z.strictObject({filters:o.z.array(V).max(12).optional(),operation:o.z.enum(["delete","insert","update","upsert"]),rows:o.z.array(o.z.record(o.z.string(),o.z.unknown())).min(1).max($).optional(),summary:o.z.string().trim().min(1).max(500).optional(),table:o.z.string().trim().min(1).max(120),values:o.z.record(o.z.string(),o.z.unknown()).optional()}),R=o.z.strictObject({actions:o.z.array(A).min(1).max(8),summary:o.z.string().trim().min(1).max(500).optional()});function g(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 z(e){return e===null||typeof e!="object"?JSON.stringify(e):Array.isArray(e)?`[${e.map(t=>z(t)).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${z(e[t])}`).join(",")}}`}function G(e){let t=2166136261;const r=z(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 ce(e,t,r){return`${I(`CONFIRM ${e} ${t}`)} #${G(r)}`}function de(e){return{confirmationPhrase:ce(e.action,e.subject,e.payload),mutationExecuted:!1,preview:e.preview,requiresConfirmation:!0,success:!0}}function X(e){if(e.context?.skipConfirmation)return null;const t=de(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 ue(e){return Object.prototype.hasOwnProperty.call(D,e)}function N(e){const t=e.trim();if(t.includes(".")||t.toLowerCase().startsWith("auth"))throw new Error("Cortex AI cannot access auth schema tables.");if(!ue(t))throw new Error(`Table "${t}" is not available to Cortex AI database tools.`);return t}function p(e){return D[e]}function v(e){return/(?:password|token|secret|api[_-]?key|private[_-]?key|credential)/i.test(e)}function b(e,t){if(!p(e).columns.includes(t))throw new Error(`Column "${t}" is not available on table "${e}".`);if(v(t))throw new Error(`Column "${t}" is protected and cannot be used through Cortex AI.`)}function K(e,t="payload"){if(Array.isArray(e)){e.forEach((r,a)=>K(r,`${t}[${a}]`));return}if(!(!e||typeof e!="object"))for(const[r,a]of Object.entries(e)){if(v(r))throw new Error(`Protected field "${t}.${r}" cannot be written through Cortex AI.`);K(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]=v(r)?B:h(a);return t}function le(e){return e.map(t=>{if(t&&typeof t=="object"&&!Array.isArray(t)){const r=t.key;if(typeof r=="string"&&j.has(r))return{key:r,value:B}}return h(t)})}function _e(e,t){if(e!=="site_settings")return;const r=JSON.stringify(t).toLowerCase();for(const a of j)if(r.includes(a))throw new Error(`The "${a}" site setting is protected.`)}function me(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 w(e,t,r){let a=t;for(const n of r)b(e,n.column),a=me(a,n);return e==="site_settings"&&(a=a.neq("key",F)),a}function pe(e,t){const r=p(e),a=t?.length?t:r.columns.filter(n=>!v(n));return a.forEach(n=>b(e,n)),a.join(",")}function J(e,t){return t.map(r=>`${r}=${String(e[r]??"")}`).join("|")}async function W(e,t,r){const a=p(t);let n=e.from(t).select(a.primaryKey.join(",")).limit(S+1);n=w(t,n,r);const{data:i,error:s}=await n;if(s)throw new Error(`Failed to preview database mutation: ${f(s)}`);const c=Array.isArray(i)?i:[];if(c.length>S)throw new Error(`Refusing to mutate more than ${S} rows.`);return c}function Q(e){const t=N(e.table),r=p(t),a=e.operation;if(r.readOnly)throw new Error(`Table "${t}" is read-only for Cortex AI.`);if(_e(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>$)throw new Error(`Refusing to mutate more than ${$} input rows.`);const n=e.rows??(e.values?[e.values]:[]);for(const i of n){K(i);for(const s of Object.keys(i))b(t,s)}for(const i of e.filters??[])b(t,i.column);return t}function Y(e){const{input:t,table:r,targetRows:a}=e,n=p(r),i=a.map(_=>J(_,n.primaryKey)).sort(),s=t.rows?.length??0,c=t.operation==="insert"||t.operation==="upsert"?s:a.length,u=t.summary||`${t.operation} ${c} ${c===1?"row":"rows"} in ${r}.`;return{affectedCount:c,operation:t.operation,sampleTargetIds:i.slice(0,10),summary:u,table:r,targetIds:i}}async function E(e){const t=e.context?.actorUserId;if(!t)return{auditError:"Missing actor user id.",auditLogged:!1};try{const{error:r}=await g(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:G(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 ye(e,t,r){const n=p(t).primaryKey.join(",");let i;e.operation==="insert"?i=r.from(t).insert(e.rows).select(n):e.operation==="upsert"?i=r.from(t).upsert(e.rows).select(n):e.operation==="update"?(i=r.from(t).update(e.values),i=w(t,i,e.filters??[]),i=i.select(n)):(i=r.from(t).delete(),i=w(t,i,e.filters??[]),i=i.select(n));const{data:s,error:c}=await i;if(c)throw new Error(f(c));return Array.isArray(s)?s:[]}async function H(e){const t=P.parse(e),a=(t.table?[N(t.table)]:Object.keys(D)).filter(n=>t.includeReadOnly||!p(n).readOnly).map(n=>{const i=p(n);return{columns:i.columns.filter(s=>!v(s)),description:i.description,primaryKey:i.primaryKey,readOnly:!!i.readOnly,table:n}});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): ${[...j].sort().join(", ")}.`,`Write-protected site_settings keys (readable, never writable here): ${[...O].sort().join(", ")}.`,"blocks.content is validated against its block_type (built-in schema or custom block definition) before any insert, upsert, or update; prefer the typed content tools, which also normalize and record revisions."],success:!0,tables:a}}async function Z(e,t){const r=M.parse(e),a=N(r.table),n=pe(a,r.columns);let i=g(t).from(a).select(n).range(r.offset,r.offset+r.limit-1);i=w(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:c}=await i;if(c)throw new Error(`Failed to read database records: ${f(c)}`);const u=Array.isArray(s)?s:[];return{columns:n.split(","),limit:r.limit,offset:r.offset,rows:le(u),success:!0,table:a}}async function q(e,t){const r=A.parse(e),a=Q(r),n=g(t);await U(r,a,t);const i=r.operation==="update"||r.operation==="delete"?await W(n,a,r.filters??[]):[],s=Y({input:r,table:a,targetRows:i}),c={input:r,targetIds:s.targetIds},u=X({action:`DATABASE ${r.operation}`,context:t,payload:c,preview:s,subject:a});if(u)return u;try{const _=await ye(r,a,n),m=t?.skipAudit?{auditLogged:!1}:await E({context:t,input:c,preview:s,status:"success",summary:String(s.summary),targetTables:[a],toolName:"execute_database_mutation"});return{affectedCount:_.length||s.affectedCount,auditLogged:m.auditLogged,...m.auditError?{auditError:m.auditError}:{},mutationExecuted:!0,operation:r.operation,sampleTargetIds:_.map(d=>J(d,p(a).primaryKey)).slice(0,10),success:!0,summary:s.summary,table:a}}catch(_){const m=f(_),d=t?.skipAudit?{auditLogged:!1}:await E({context:t,errorMessage:m,input:c,preview:s,status:"failure",summary:String(s.summary),targetTables:[a],toolName:"execute_database_mutation"});return{auditLogged:d.auditLogged,...d.auditError?{auditError:d.auditError}:{},message:`Database mutation failed: ${m}`,mutationExecuted:!1,operation:r.operation,success:!1,table:a}}}async function ee(e,t){const r=R.parse(e),a=[];for(const d of r.actions){const y=Q(d);await U(d,y,t);const l=d.operation==="update"||d.operation==="delete"?await W(g(t),y,d.filters??[]):[];a.push({input:d,preview:Y({input:d,table:y,targetRows:l}),table:y})}const n=a.map(({preview:d})=>String(d.summary)),i={actionCount:a.length,actionSummaries:n,summary:r.summary||`Run ${a.length} confirmed database actions.`,tables:Array.from(new Set(a.map(d=>d.table)))},s=a.map(({input:d,preview:y,table:l})=>({input:d,table:l,targetIds:y.targetIds})),c=X({action:"DATABASE ACTION PLAN",context:t,payload:s,preview:i,subject:`${a.length} actions`});if(c)return c;const u=[];let _=!1;for(const[d,y]of a.entries()){const l=await q(y.input,{...t,skipAudit:!0,skipConfirmation:!0});if(u.push(l),l&&typeof l=="object"&&l.mutationExecuted===!0&&(_=!0),!l||typeof l!="object"||l.success===!1){const C=await E({context:t,errorMessage:l&&typeof l=="object"&&typeof l.message=="string"?l.message:`Database action ${d+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:d,message:l&&typeof l=="object"&&typeof l.message=="string"?l.message:`Database action ${d+1} failed.`,mutationExecuted:_,results:u,success:!1}}}const m=await E({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:_,results:u,success:!0,summary:r.summary??null}}function fe(e){return{describe_database_schema:k.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=>H(t),inputSchema:P,strict:!0}),execute_database_action_plan:k.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=>ee(t,e),inputSchema:R,strict:!0}),execute_database_mutation:k.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=>q(t,e),inputSchema:A,strict:!0}),read_database_records:k.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=>Z(t,e),inputSchema:M,strict:!0})}}exports.createCortexDatabaseAgentTools=fe;exports.describeDatabaseSchemaInputSchema=P;exports.executeDatabaseActionPlan=ee;exports.executeDatabaseActionPlanInputSchema=R;exports.executeDatabaseMutation=q;exports.executeDatabaseMutationInputSchema=A;exports.executeDescribeDatabaseSchema=H;exports.executeReadDatabaseRecords=Z;exports.readDatabaseRecordsInputSchema=M;
@@ -1,3 +1,4 @@
1
+ import { BlockContentValidator } from './block-content-schemas';
1
2
  import { z } from './zod-config';
2
3
  type SupabaseLike = {
3
4
  from: (table: string) => any;
@@ -8,6 +9,12 @@ type ToolExecutionContext = {
8
9
  skipAudit?: boolean;
9
10
  skipConfirmation?: boolean;
10
11
  supabase?: SupabaseLike;
12
+ /**
13
+ * The app's block schema validator (apps/nextblock/lib/blocks/blockRegistry.ts),
14
+ * injected by both routes. When absent the mirrored schemas in
15
+ * block-content-schemas.ts apply, so `blocks.content` is never written unchecked.
16
+ */
17
+ validateBlockContent?: BlockContentValidator;
11
18
  };
12
19
  export declare const describeDatabaseSchemaInputSchema: z.ZodObject<{
13
20
  includeReadOnly: z.ZodDefault<z.ZodBoolean>;