@nextblock-cms/cortex 0.20.3 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client.cjs.js +1 -1
- package/client.es.js +3 -7
- package/index.cjs.js +1 -1
- package/index.es.js +24 -277
- package/lib/ai-block-generation.cjs.js +3 -4
- package/lib/ai-block-generation.es.js +143 -182
- package/lib/ai-client.cjs.js +1 -1
- package/lib/ai-client.d.ts +1 -1
- package/lib/ai-client.es.js +101 -135
- package/lib/ai-config.cjs.js +1 -1
- package/lib/ai-config.es.js +89 -108
- package/lib/ai-cortex-widget-builder.cjs.js +1 -1
- package/lib/ai-cortex-widget-builder.es.js +56 -70
- package/lib/ai-global-agent-content-ops-tools.cjs.js +1 -1
- package/lib/ai-global-agent-content-ops-tools.d.ts +1943 -68
- package/lib/ai-global-agent-content-ops-tools.es.js +185 -199
- package/lib/ai-global-agent-custom-block-tools.cjs.js +1 -1
- package/lib/ai-global-agent-custom-block-tools.d.ts +2160 -95
- package/lib/ai-global-agent-custom-block-tools.es.js +226 -223
- package/lib/ai-global-agent-db-tools.cjs.js +1 -1
- package/lib/ai-global-agent-db-tools.d.ts +2708 -98
- package/lib/ai-global-agent-db-tools.es.js +1013 -986
- package/lib/ai-global-agent-ecommerce.cjs.js +1 -1
- package/lib/ai-global-agent-ecommerce.es.js +3 -7
- package/lib/ai-global-agent-site-tools.cjs.js +2 -3
- package/lib/ai-global-agent-site-tools.d.ts +10695 -500
- package/lib/ai-global-agent-site-tools.es.js +750 -757
- package/lib/ai-global-agent-theming-tools.cjs.js +1 -3
- package/lib/ai-global-agent-theming-tools.d.ts +2905 -105
- package/lib/ai-global-agent-theming-tools.es.js +326 -396
- package/lib/ai-global-agent-tools.cjs.js +2 -2
- package/lib/ai-global-agent-tools.d.ts +4 -2230
- package/lib/ai-global-agent-tools.es.js +3899 -4328
- package/lib/ai-key-crypto.cjs.js +1 -1
- package/lib/ai-key-crypto.es.js +63 -82
- package/lib/ai-key-verification.cjs.js +1 -1
- package/lib/ai-key-verification.es.js +74 -63
- package/lib/ai-model-catalog.cjs.js +1 -1
- package/lib/ai-model-catalog.es.js +18 -22
- package/lib/ai-model-registry.cjs.js +2 -2
- package/lib/ai-model-registry.es.js +246 -309
- package/lib/ai-seo-metadata.cjs.js +2 -3
- package/lib/ai-seo-metadata.es.js +143 -185
- package/lib/ai-vision.cjs.js +2 -2
- package/lib/ai-vision.d.ts +6 -6
- package/lib/ai-vision.es.js +161 -215
- package/lib/block-content-schemas.cjs.js +1 -1
- package/lib/block-content-schemas.es.js +324 -254
- package/lib/cortex-widget-registry.cjs.js +1 -1
- package/lib/cortex-widget-registry.es.js +35 -43
- package/lib/cortex-widget-schema.cjs.js +2 -3
- package/lib/cortex-widget-schema.es.js +280 -309
- package/lib/editor-document-from-html.cjs.js +1 -1
- package/lib/editor-document-from-html.es.js +334 -278
- package/lib/fetch-host-guard.cjs.js +1 -0
- package/lib/fetch-host-guard.d.ts +2 -0
- package/lib/fetch-host-guard.es.js +30 -0
- package/lib/mcp-server.cjs.js +1 -1
- package/lib/mcp-server.es.js +155 -173
- package/lib/mcp-tokens.cjs.js +1 -1
- package/lib/mcp-tokens.es.js +95 -107
- package/lib/mcp-tool-registry.cjs.js +5 -6
- package/lib/mcp-tool-registry.es.js +533 -411
- package/lib/site-brief.cjs.js +2 -2
- package/lib/site-brief.es.js +102 -108
- package/lib/vision-image-download.cjs.js +1 -0
- package/lib/vision-image-download.d.ts +43 -0
- package/lib/vision-image-download.es.js +120 -0
- package/lib/zod-config.cjs.js +1 -1
- package/lib/zod-config.es.js +5 -6
- package/package.json +8 -8
|
@@ -1,230 +1,233 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
});
|
|
1
|
+
import { z as e } from "./zod-config.es.js";
|
|
2
|
+
import { tool as t } from "ai";
|
|
3
|
+
import { revalidatePath as n, revalidateTag as r } from "next/cache";
|
|
4
|
+
//#region libs/cortex/src/lib/ai-global-agent-custom-block-tools.ts
|
|
5
|
+
var i = "id, slug, name, description, fields, layout_schema, is_original", a = e.strictObject({
|
|
6
|
+
context: e.string().trim().max(3e3).optional().describe("Optional extra constraints or brand/style guidance for the generated block."),
|
|
7
|
+
prompt: e.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.\"")
|
|
8
|
+
}), o = e.strictObject({
|
|
9
|
+
prompt: e.string().trim().min(3).max(4e3).describe("Description of the changes to apply. The block is regenerated using its existing definition as context."),
|
|
10
|
+
slug: e.string().trim().min(1).max(120).describe("Slug of the existing custom block to edit.")
|
|
11
|
+
}), s = e.strictObject({ slug: e.string().trim().min(1).max(120).describe("Slug of the custom block definition to delete.") }), c = e.strictObject({ query: e.string().trim().max(120).optional().describe("Optional text filter on name or slug.") });
|
|
17
12
|
function l(e) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return e.supabase;
|
|
13
|
+
if (!e?.supabase) throw Error("A Supabase service client is required to manage custom block definitions.");
|
|
14
|
+
return e.supabase;
|
|
21
15
|
}
|
|
22
|
-
function
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
function u(e) {
|
|
17
|
+
if (!e?.actorUserId) throw Error("Managing custom block definitions requires an authenticated admin actor.");
|
|
18
|
+
return e.actorUserId;
|
|
19
|
+
}
|
|
20
|
+
function d(e) {
|
|
21
|
+
return JSON.parse(JSON.stringify(e));
|
|
26
22
|
}
|
|
27
|
-
function
|
|
28
|
-
|
|
23
|
+
function f(e) {
|
|
24
|
+
let t = Array.isArray(e?.fields) ? e.fields : [];
|
|
25
|
+
return {
|
|
26
|
+
fieldCount: t.length,
|
|
27
|
+
fields: t.map((e) => ({
|
|
28
|
+
key: e?.key,
|
|
29
|
+
label: e?.label,
|
|
30
|
+
type: e?.type
|
|
31
|
+
})),
|
|
32
|
+
id: e?.id,
|
|
33
|
+
name: e?.name,
|
|
34
|
+
slug: e?.slug
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
var p = 24e3;
|
|
38
|
+
function m(e) {
|
|
39
|
+
let t = `You are editing an existing custom block named "${e.name ?? "Untitled"}". Keep its overall purpose and only apply the requested changes.`, n = `${t} Existing definition: ${JSON.stringify({
|
|
40
|
+
fields: e.fields,
|
|
41
|
+
layout_schema: e.layout_schema,
|
|
42
|
+
name: e.name
|
|
43
|
+
})}`;
|
|
44
|
+
return n.length <= p ? n : `${t} Existing fields: ${JSON.stringify({
|
|
45
|
+
fields: e.fields,
|
|
46
|
+
name: e.name
|
|
47
|
+
})} (The existing layout was too large to include — rebuild a layout that renders these fields.)`.slice(0, p);
|
|
48
|
+
}
|
|
49
|
+
function h(e, t) {
|
|
50
|
+
let n = t?.cortexAiApiKey || void 0;
|
|
51
|
+
return {
|
|
52
|
+
apiKey: n,
|
|
53
|
+
context: e.context,
|
|
54
|
+
modelSelection: n && t?.cortexAiModelSelection ? t.cortexAiModelSelection : void 0,
|
|
55
|
+
prompt: e.prompt
|
|
56
|
+
};
|
|
29
57
|
}
|
|
30
58
|
function g(e) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
59
|
+
try {
|
|
60
|
+
let t = n, i = r;
|
|
61
|
+
i("custom-block-definitions", "max"), e?.id && i(`custom-block-definitions:${e.id}`, "max"), e?.slug && i(`custom-block-definitions:${e.slug}`, "max"), i("dynamic-layout-engine", "max"), t("/cms/custom-blocks"), t("/cms/blocks");
|
|
62
|
+
} catch {}
|
|
63
|
+
}
|
|
64
|
+
function _(e) {
|
|
65
|
+
return (e || "").replace(/\s+/g, " ").trim().toUpperCase();
|
|
66
|
+
}
|
|
67
|
+
function v(e) {
|
|
68
|
+
return `CONFIRM DELETE CUSTOM BLOCK ${e.toUpperCase()}`;
|
|
69
|
+
}
|
|
70
|
+
function y(e, t) {
|
|
71
|
+
return e?.skipConfirmation ? !0 : _(e?.latestUserMessage).includes(_(t));
|
|
72
|
+
}
|
|
73
|
+
function b(e) {
|
|
74
|
+
if (e && typeof e == "object") {
|
|
75
|
+
let t = e;
|
|
76
|
+
if (t.code === "23505") return "A custom block with that slug already exists. Choose a different name or edit the existing one.";
|
|
77
|
+
if (typeof t.message == "string" && t.message) return t.message;
|
|
78
|
+
}
|
|
79
|
+
return e instanceof Error ? e.message : "Unknown error.";
|
|
80
|
+
}
|
|
81
|
+
async function x(e, t) {
|
|
82
|
+
try {
|
|
83
|
+
let n = l(t);
|
|
84
|
+
u(t);
|
|
85
|
+
let [{ generateCortexWidgetDefinition: r }, { insertCortexWidgetDefinition: i }] = await Promise.all([import("./ai-cortex-widget-builder.es.js"), import("./cortex-widget-registry.es.js")]), a = await i(n, (await r(h(e, t))).definition);
|
|
86
|
+
return g(a), {
|
|
87
|
+
definition: f(a),
|
|
88
|
+
editUrl: `/cms/custom-blocks/${a.id}/edit`,
|
|
89
|
+
mutationExecuted: !0,
|
|
90
|
+
success: !0
|
|
91
|
+
};
|
|
92
|
+
} catch (e) {
|
|
93
|
+
return {
|
|
94
|
+
mutationExecuted: !1,
|
|
95
|
+
message: b(e),
|
|
96
|
+
success: !1
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async function S(e, t) {
|
|
101
|
+
try {
|
|
102
|
+
let n = l(t);
|
|
103
|
+
u(t);
|
|
104
|
+
let { data: r } = await n.from("custom_block_definitions").select(i).eq("slug", e.slug).maybeSingle();
|
|
105
|
+
if (!r) return {
|
|
106
|
+
mutationExecuted: !1,
|
|
107
|
+
message: `No custom block found with slug "${e.slug}".`,
|
|
108
|
+
success: !1
|
|
109
|
+
};
|
|
110
|
+
let [{ generateCortexWidgetDefinition: a }, { customBlockDefinitionCreateSchema: o }] = await Promise.all([import("./ai-cortex-widget-builder.es.js"), import("@nextblock-cms/utils/custom-blocks")]), s = await a(h({
|
|
111
|
+
context: m(r),
|
|
112
|
+
prompt: e.prompt
|
|
113
|
+
}, t)), c = o.parse({
|
|
114
|
+
...s.definition,
|
|
115
|
+
is_original: r.is_original,
|
|
116
|
+
slug: r.slug
|
|
117
|
+
}), { data: p, error: _ } = await n.from("custom_block_definitions").update({
|
|
118
|
+
description: c.description,
|
|
119
|
+
fields: d(c.fields),
|
|
120
|
+
layout_schema: d(c.layout_schema),
|
|
121
|
+
name: c.name
|
|
122
|
+
}).eq("id", r.id).select(i).single();
|
|
123
|
+
return _ || !p ? {
|
|
124
|
+
mutationExecuted: !1,
|
|
125
|
+
message: _?.message ?? "Failed to update custom block.",
|
|
126
|
+
success: !1
|
|
127
|
+
} : (g(p), {
|
|
128
|
+
definition: f(p),
|
|
129
|
+
editUrl: `/cms/custom-blocks/${r.id}/edit`,
|
|
130
|
+
mutationExecuted: !0,
|
|
131
|
+
success: !0
|
|
132
|
+
});
|
|
133
|
+
} catch (e) {
|
|
134
|
+
return {
|
|
135
|
+
mutationExecuted: !1,
|
|
136
|
+
message: b(e),
|
|
137
|
+
success: !1
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async function C(e, t) {
|
|
142
|
+
try {
|
|
143
|
+
let n = l(t);
|
|
144
|
+
u(t);
|
|
145
|
+
let { data: r } = await n.from("custom_block_definitions").select("id, slug, name").eq("slug", e.slug).maybeSingle();
|
|
146
|
+
if (!r) return {
|
|
147
|
+
mutationExecuted: !1,
|
|
148
|
+
message: `No custom block found with slug "${e.slug}".`,
|
|
149
|
+
success: !1
|
|
150
|
+
};
|
|
151
|
+
let i = v(r.slug);
|
|
152
|
+
if (!y(t, i)) return {
|
|
153
|
+
confirmationPhrase: i,
|
|
154
|
+
mutationExecuted: !1,
|
|
155
|
+
preview: { summary: `Delete the custom block "${r.name}" (${r.slug}). Pages still using it will stop rendering it until replaced. This cannot be undone.` },
|
|
156
|
+
requiresConfirmation: !0,
|
|
157
|
+
success: !0
|
|
158
|
+
};
|
|
159
|
+
let { error: a } = await n.from("custom_block_definitions").delete().eq("id", r.id);
|
|
160
|
+
return a ? {
|
|
161
|
+
mutationExecuted: !1,
|
|
162
|
+
message: `Failed to delete custom block: ${a.message}`,
|
|
163
|
+
success: !1
|
|
164
|
+
} : (g(r), {
|
|
165
|
+
deleted: {
|
|
166
|
+
name: r.name,
|
|
167
|
+
slug: r.slug
|
|
168
|
+
},
|
|
169
|
+
mutationExecuted: !0,
|
|
170
|
+
success: !0
|
|
171
|
+
});
|
|
172
|
+
} catch (e) {
|
|
173
|
+
return {
|
|
174
|
+
mutationExecuted: !1,
|
|
175
|
+
message: b(e),
|
|
176
|
+
success: !1
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async function w(e, t) {
|
|
181
|
+
try {
|
|
182
|
+
let { data: n, error: r } = await l(t).from("custom_block_definitions").select("id, slug, name, description, fields, is_original").order("name", { ascending: !0 });
|
|
183
|
+
if (r) return {
|
|
184
|
+
message: r.message,
|
|
185
|
+
success: !1
|
|
186
|
+
};
|
|
187
|
+
let i = Array.isArray(n) ? n : [];
|
|
188
|
+
if (e.query) {
|
|
189
|
+
let t = e.query.toLowerCase();
|
|
190
|
+
i = i.filter((e) => String(e.name || "").toLowerCase().includes(t) || String(e.slug || "").toLowerCase().includes(t));
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
blocks: i.map((e) => f(e)),
|
|
194
|
+
count: i.length,
|
|
195
|
+
success: !0
|
|
196
|
+
};
|
|
197
|
+
} catch (e) {
|
|
198
|
+
return {
|
|
199
|
+
message: b(e),
|
|
200
|
+
success: !1
|
|
201
|
+
};
|
|
202
|
+
}
|
|
70
203
|
}
|
|
71
204
|
function T(e) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
} catch (s) {
|
|
102
|
-
return { mutationExecuted: !1, message: d(s), success: !1 };
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
async function $(e, t) {
|
|
106
|
-
try {
|
|
107
|
-
const s = l(t);
|
|
108
|
-
f(t);
|
|
109
|
-
const { data: i } = await s.from("custom_block_definitions").select(h).eq("slug", e.slug).maybeSingle();
|
|
110
|
-
if (!i)
|
|
111
|
-
return { mutationExecuted: !1, message: `No custom block found with slug "${e.slug}".`, success: !1 };
|
|
112
|
-
const [{ generateCortexWidgetDefinition: r }, { customBlockDefinitionCreateSchema: o }] = await Promise.all([
|
|
113
|
-
import("./ai-cortex-widget-builder.es.js"),
|
|
114
|
-
import("@nextblock-cms/utils/custom-blocks")
|
|
115
|
-
]), n = await r(
|
|
116
|
-
C(
|
|
117
|
-
{
|
|
118
|
-
context: O(i),
|
|
119
|
-
prompt: e.prompt
|
|
120
|
-
},
|
|
121
|
-
t
|
|
122
|
-
)
|
|
123
|
-
), c = o.parse({
|
|
124
|
-
...n.definition,
|
|
125
|
-
is_original: i.is_original,
|
|
126
|
-
slug: i.slug
|
|
127
|
-
}), { data: m, error: b } = await s.from("custom_block_definitions").update({
|
|
128
|
-
description: c.description,
|
|
129
|
-
fields: k(c.fields),
|
|
130
|
-
layout_schema: k(c.layout_schema),
|
|
131
|
-
name: c.name
|
|
132
|
-
}).eq("id", i.id).select(h).single();
|
|
133
|
-
return b || !m ? { mutationExecuted: !1, message: b?.message ?? "Failed to update custom block.", success: !1 } : (p(m), {
|
|
134
|
-
definition: g(m),
|
|
135
|
-
editUrl: `/cms/custom-blocks/${i.id}/edit`,
|
|
136
|
-
mutationExecuted: !0,
|
|
137
|
-
success: !0
|
|
138
|
-
});
|
|
139
|
-
} catch (s) {
|
|
140
|
-
return { mutationExecuted: !1, message: d(s), success: !1 };
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
async function B(e, t) {
|
|
144
|
-
try {
|
|
145
|
-
const s = l(t);
|
|
146
|
-
f(t);
|
|
147
|
-
const { data: i } = await s.from("custom_block_definitions").select("id, slug, name").eq("slug", e.slug).maybeSingle();
|
|
148
|
-
if (!i)
|
|
149
|
-
return { mutationExecuted: !1, message: `No custom block found with slug "${e.slug}".`, success: !1 };
|
|
150
|
-
const r = T(i.slug);
|
|
151
|
-
if (!q(t, r))
|
|
152
|
-
return {
|
|
153
|
-
confirmationPhrase: r,
|
|
154
|
-
mutationExecuted: !1,
|
|
155
|
-
preview: {
|
|
156
|
-
summary: `Delete the custom block "${i.name}" (${i.slug}). Pages still using it will stop rendering it until replaced. This cannot be undone.`
|
|
157
|
-
},
|
|
158
|
-
requiresConfirmation: !0,
|
|
159
|
-
success: !0
|
|
160
|
-
};
|
|
161
|
-
const { error: o } = await s.from("custom_block_definitions").delete().eq("id", i.id);
|
|
162
|
-
return o ? { mutationExecuted: !1, message: `Failed to delete custom block: ${o.message}`, success: !1 } : (p(i), {
|
|
163
|
-
deleted: { name: i.name, slug: i.slug },
|
|
164
|
-
mutationExecuted: !0,
|
|
165
|
-
success: !0
|
|
166
|
-
});
|
|
167
|
-
} catch (s) {
|
|
168
|
-
return { mutationExecuted: !1, message: d(s), success: !1 };
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
async function D(e, t) {
|
|
172
|
-
try {
|
|
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 });
|
|
174
|
-
if (r)
|
|
175
|
-
return { message: r.message, success: !1 };
|
|
176
|
-
let o = Array.isArray(i) ? i : [];
|
|
177
|
-
if (e.query) {
|
|
178
|
-
const n = e.query.toLowerCase();
|
|
179
|
-
o = o.filter(
|
|
180
|
-
(c) => String(c.name || "").toLowerCase().includes(n) || String(c.slug || "").toLowerCase().includes(n)
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
return {
|
|
184
|
-
blocks: o.map((n) => g(n)),
|
|
185
|
-
count: o.length,
|
|
186
|
-
success: !0
|
|
187
|
-
};
|
|
188
|
-
} catch (s) {
|
|
189
|
-
return { message: d(s), success: !1 };
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
function N(e) {
|
|
193
|
-
return {
|
|
194
|
-
create_custom_block: u({
|
|
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.',
|
|
196
|
-
execute: (t) => A(t, e),
|
|
197
|
-
inputSchema: w,
|
|
198
|
-
strict: !0
|
|
199
|
-
}),
|
|
200
|
-
delete_custom_block: u({
|
|
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.",
|
|
202
|
-
execute: (t) => B(t, e),
|
|
203
|
-
inputSchema: E,
|
|
204
|
-
strict: !0
|
|
205
|
-
}),
|
|
206
|
-
list_custom_blocks: u({
|
|
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.",
|
|
208
|
-
execute: (t) => D(t, e),
|
|
209
|
-
inputSchema: S,
|
|
210
|
-
strict: !0
|
|
211
|
-
}),
|
|
212
|
-
update_custom_block: u({
|
|
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.",
|
|
214
|
-
execute: (t) => $(t, e),
|
|
215
|
-
inputSchema: _,
|
|
216
|
-
strict: !0
|
|
217
|
-
})
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
export {
|
|
221
|
-
N as createCortexCustomBlockTools,
|
|
222
|
-
w as createCustomBlockInputSchema,
|
|
223
|
-
E as deleteCustomBlockInputSchema,
|
|
224
|
-
A as executeCreateCustomBlock,
|
|
225
|
-
B as executeDeleteCustomBlock,
|
|
226
|
-
D as executeListCustomBlocks,
|
|
227
|
-
$ as executeUpdateCustomBlock,
|
|
228
|
-
S as listCustomBlocksInputSchema,
|
|
229
|
-
_ as updateCustomBlockInputSchema
|
|
230
|
-
};
|
|
205
|
+
return {
|
|
206
|
+
create_custom_block: t({
|
|
207
|
+
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.",
|
|
208
|
+
execute: (t) => x(t, e),
|
|
209
|
+
inputSchema: a,
|
|
210
|
+
strict: !0
|
|
211
|
+
}),
|
|
212
|
+
delete_custom_block: t({
|
|
213
|
+
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.",
|
|
214
|
+
execute: (t) => C(t, e),
|
|
215
|
+
inputSchema: s,
|
|
216
|
+
strict: !0
|
|
217
|
+
}),
|
|
218
|
+
list_custom_blocks: t({
|
|
219
|
+
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.",
|
|
220
|
+
execute: (t) => w(t, e),
|
|
221
|
+
inputSchema: c,
|
|
222
|
+
strict: !0
|
|
223
|
+
}),
|
|
224
|
+
update_custom_block: t({
|
|
225
|
+
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.",
|
|
226
|
+
execute: (t) => S(t, e),
|
|
227
|
+
inputSchema: o,
|
|
228
|
+
strict: !0
|
|
229
|
+
})
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
//#endregion
|
|
233
|
+
export { T as createCortexCustomBlockTools, a as createCustomBlockInputSchema, s as deleteCustomBlockInputSchema, x as executeCreateCustomBlock, C as executeDeleteCustomBlock, w as executeListCustomBlocks, S as executeUpdateCustomBlock, c as listCustomBlocksInputSchema, o as updateCustomBlockInputSchema };
|
|
@@ -1 +1 @@
|
|
|
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
|
+
require("./zod-config.cjs.js");const e=require("./site-brief.cjs.js"),t=require("./block-content-schemas.cjs.js");let n=require("ai"),r=require("zod");var i=100,a=20,o=100,s=20,c=`[REDACTED]`,l=`cortex_ai_openrouter_api_key`,u=new Set([l,`bot_protection_secret`,`cortex_ai_pexels_api_key`,`cortex_ai_unsplash_access_key`,`email_secret`,`payment_secret`]),d=new Set([`cortex_ai_build_session`,`is_admin_created`,`migration_baseline_generation`,`security_settings`]),f={active_logo_id:r.z.string().uuid().nullable(),cortex_ai_site_brief:e.cortexSiteBriefSchema,footer_copyright:r.z.record(r.z.string().trim().min(2).max(12),r.z.string().max(500)),footer_show_attribution:r.z.boolean(),global_css:r.z.string().max(2e5),onboarding_state:r.z.record(r.z.string(),r.z.unknown()),site_description:r.z.string().max(1e3),site_keywords:r.z.string().max(1e3),site_title:r.z.string().max(200)};function p(e){return e.map(e=>{let t=e.path.map(String).join(`.`);return t?`${t}: ${e.message}`:e.message}).join(`; `)}function m(e,t){if(d.has(e))throw Error(`The "${e}" site setting cannot be written through Cortex AI database tools.`);let n=f[e];if(!n)return;let r=n.safeParse(t);if(!r.success)throw Error(`Invalid value for site setting "${e}": ${p(r.error.issues)}`)}async function h(e){let n=typeof e.blockType==`string`?e.blockType:``;if(!n)throw Error(`${e.label}: block_type is required.`);if(!e.content||typeof e.content!=`object`||Array.isArray(e.content))throw Error(`${e.label}: content must be a JSON object.`);let r=e.content;if(t.isValidBlockType(n)){let i=t.validateCortexBlockContent(n,r,e.context);if(!i.isValid)throw Error(`${e.label}: content is invalid for block type "${n}": ${i.errors.join(`; `)}`);return}let i=(await e.definitions()).find(e=>e.slug===n);if(!i)throw Error(`${e.label}: "${n}" is neither a built-in block type nor a custom block slug. Use list_custom_blocks to see the custom block definitions.`);let a=t.validateCustomBlockInstanceContent(i,r);if(!a.isValid)throw Error(`${e.label}: content is invalid for custom block "${n}": ${a.errors.join(`; `)}`)}async function g(e,n,r){if(n===`site_settings`){for(let t of e.rows??[])typeof t.key==`string`&&m(t.key,t.value);if(e.operation===`update`&&e.values){let t=typeof e.values.key==`string`?e.values.key:null,n=(e.filters??[]).find(e=>e.column===`key`&&e.operator===`eq`&&typeof e.value==`string`),r=t??(n?String(n.value):null);r&&(`value`in e.values?m(r,e.values.value):d.has(r)&&m(r,void 0))}return}if(n!==`blocks`)return;let i=null,a=()=>i??=t.loadCustomBlockDefinitions(T(r));if(e.operation===`insert`||e.operation===`upsert`){for(let[t,n]of(e.rows??[]).entries())await h({blockType:n.block_type,content:n.content??{},context:r,definitions:a,label:`rows[${t}]`});return}if(e.operation===`update`&&e.values){let t=`content`in e.values,i=`block_type`in e.values;if(!t&&!i)return;if(i&&!t)throw Error(`Changing block_type requires the new content for that type in the same update.`);let o=new Set;if(i)o.add(String(e.values.block_type));else{let t=T(r).from(`blocks`).select(`id, block_type`).limit(101);t=U(n,t,e.filters??[]);let{data:i,error:a}=await t;if(a)throw Error(`Failed to read the blocks to update: ${E(a)}`);for(let e of Array.isArray(i)?i:[])o.add(String(e.block_type??``))}for(let t of o)await h({blockType:t,content:e.values.content,context:r,definitions:a,label:`values (block_type "${t}")`})}}var _={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`.split(`.`),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`.split(`.`),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`]}},v=r.z.enum([`eq`,`neq`,`gt`,`gte`,`lt`,`lte`,`ilike`,`in`,`is`]),y=r.z.strictObject({column:r.z.string().trim().min(1).max(120),operator:v.default(`eq`),value:r.z.unknown()}),b=r.z.strictObject({ascending:r.z.boolean().default(!0),column:r.z.string().trim().min(1).max(120)}),x=r.z.strictObject({includeReadOnly:r.z.boolean().default(!0),table:r.z.string().trim().min(1).max(120).optional()}),S=r.z.strictObject({columns:r.z.array(r.z.string().trim().min(1).max(120)).min(1).max(40).optional(),filters:r.z.array(y).max(12).default([]),limit:r.z.number().int().min(1).max(i).default(a),offset:r.z.number().int().min(0).max(1e4).default(0),orderBy:b.optional(),table:r.z.string().trim().min(1).max(120)}),C=r.z.strictObject({filters:r.z.array(y).max(12).optional(),operation:r.z.enum([`delete`,`insert`,`update`,`upsert`]),rows:r.z.array(r.z.record(r.z.string(),r.z.unknown())).min(1).max(s).optional(),summary:r.z.string().trim().min(1).max(500).optional(),table:r.z.string().trim().min(1).max(120),values:r.z.record(r.z.string(),r.z.unknown()).optional()}),w=r.z.strictObject({actions:r.z.array(C).min(1).max(8),summary:r.z.string().trim().min(1).max(500).optional()});function T(e){if(!e?.supabase)throw Error(`Cortex AI database tools require a Supabase client.`);return e.supabase}function E(e){return e?typeof e==`object`&&`message`in e?String(e.message||`Unknown database error.`):String(e):`Unknown database error.`}function D(e){return typeof e!=`object`||!e?JSON.stringify(e):Array.isArray(e)?`[${e.map(e=>D(e)).join(`,`)}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${D(e[t])}`).join(`,`)}}`}function O(e){let t=2166136261,n=D(e);for(let e=0;e<n.length;e++)t^=n.charCodeAt(e),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,`0`)}function k(e){return e.replace(/\s+/g,` `).trim().toUpperCase()}function A(e,t,n){return`${k(`CONFIRM ${e} ${t}`)} #${O(n)}`}function j(e){return{confirmationPhrase:A(e.action,e.subject,e.payload),mutationExecuted:!1,preview:e.preview,requiresConfirmation:!0,success:!0}}function M(e){if(e.context?.skipConfirmation)return null;let t=j(e),n=k(e.context?.latestUserMessage||``),r=k(t.confirmationPhrase);return n&&!n.includes(r)?{...t,message:`The database target changed or the confirmation did not match. Please review and confirm again.`}:n.includes(r)?null:t}function N(e){return Object.prototype.hasOwnProperty.call(_,e)}function P(e){let t=e.trim();if(t.includes(`.`)||t.toLowerCase().startsWith(`auth`))throw Error(`Cortex AI cannot access auth schema tables.`);if(!N(t))throw Error(`Table "${t}" is not available to Cortex AI database tools.`);return t}function F(e){return _[e]}function I(e){return/(?:password|token|secret|api[_-]?key|private[_-]?key|credential)/i.test(e)}function L(e,t){if(!F(e).columns.includes(t))throw Error(`Column "${t}" is not available on table "${e}".`);if(I(t))throw Error(`Column "${t}" is protected and cannot be used through Cortex AI.`)}function R(e,t=`payload`){if(Array.isArray(e)){e.forEach((e,n)=>R(e,`${t}[${n}]`));return}if(e&&typeof e==`object`)for(let[n,r]of Object.entries(e)){if(I(n))throw Error(`Protected field "${t}.${n}" cannot be written through Cortex AI.`);R(r,`${t}.${n}`)}}function z(e){if(Array.isArray(e))return e.map(e=>z(e));if(!e||typeof e!=`object`)return e;let t={};for(let[n,r]of Object.entries(e))t[n]=I(n)?c:z(r);return t}function B(e){return e.map(e=>{if(e&&typeof e==`object`&&!Array.isArray(e)){let t=e.key;if(typeof t==`string`&&u.has(t))return{key:t,value:c}}return z(e)})}function V(e,t){if(e!==`site_settings`)return;let n=JSON.stringify(t).toLowerCase();for(let e of u)if(n.includes(e))throw Error(`The "${e}" site setting is protected.`)}function H(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 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 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 U(e,t,n){let r=t;for(let t of n)L(e,t.column),r=H(r,t);return e===`site_settings`&&(r=r.neq(`key`,l)),r}function W(e,t){let n=F(e),r=t?.length?t:n.columns.filter(e=>!I(e));return r.forEach(t=>L(e,t)),r.join(`,`)}function G(e,t){return t.map(t=>`${t}=${String(e[t]??``)}`).join(`|`)}async function K(e,t,n){let r=F(t),i=e.from(t).select(r.primaryKey.join(`,`)).limit(101);i=U(t,i,n);let{data:a,error:s}=await i;if(s)throw Error(`Failed to preview database mutation: ${E(s)}`);let c=Array.isArray(a)?a:[];if(c.length>o)throw Error(`Refusing to mutate more than ${o} rows.`);return c}function q(e){let t=P(e.table),n=F(t),r=e.operation;if(n.readOnly)throw Error(`Table "${t}" is read-only for Cortex AI.`);if(V(t,e),(r===`update`||r===`delete`)&&(!e.filters||e.filters.length===0))throw Error(`${r} operations require at least one filter.`);if((r===`insert`||r===`upsert`)&&(!e.rows||e.rows.length===0))throw Error(`${r} operations require rows.`);if(r===`update`&&(!e.values||Object.keys(e.values).length===0))throw Error(`update operations require values.`);if(e.rows&&e.rows.length>s)throw Error(`Refusing to mutate more than ${s} input rows.`);let i=e.rows??(e.values?[e.values]:[]);for(let e of i){R(e);for(let n of Object.keys(e))L(t,n)}for(let n of e.filters??[])L(t,n.column);return t}function J(e){let{input:t,table:n,targetRows:r}=e,i=F(n),a=r.map(e=>G(e,i.primaryKey)).sort(),o=t.rows?.length??0,s=t.operation===`insert`||t.operation===`upsert`?o:r.length,c=t.summary||`${t.operation} ${s} ${s===1?`row`:`rows`} in ${n}.`;return{affectedCount:s,operation:t.operation,sampleTargetIds:a.slice(0,10),summary:c,table:n,targetIds:a}}async function Y(e){let t=e.context?.actorUserId;if(!t)return{auditError:`Missing actor user id.`,auditLogged:!1};try{let{error:n}=await T(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:z(e.input),payload_hash:O(e.input),preview:z(e.preview),status:e.status,target_tables:e.targetTables,tool_name:e.toolName});return n?{auditError:E(n),auditLogged:!1}:{auditLogged:!0}}catch(e){return{auditError:E(e),auditLogged:!1}}}async function ee(e,t,n){let r=F(t).primaryKey.join(`,`),i;e.operation===`insert`?i=n.from(t).insert(e.rows).select(r):e.operation===`upsert`?i=n.from(t).upsert(e.rows).select(r):e.operation===`update`?(i=n.from(t).update(e.values),i=U(t,i,e.filters??[]),i=i.select(r)):(i=n.from(t).delete(),i=U(t,i,e.filters??[]),i=i.select(r));let{data:a,error:o}=await i;if(o)throw Error(E(o));return Array.isArray(a)?a:[]}async function X(e){let t=x.parse(e),n=(t.table?[P(t.table)]:Object.keys(_)).filter(e=>t.includeReadOnly||!F(e).readOnly).map(e=>{let t=F(e);return{columns:t.columns.filter(e=>!I(e)),description:t.description,primaryKey:t.primaryKey,readOnly:!!t.readOnly,table:e}});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): ${[...u].sort().join(`, `)}.`,`Write-protected site_settings keys (readable, never writable here): ${[...d].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:n}}async function Z(e,t){let n=S.parse(e),r=P(n.table),i=W(r,n.columns),a=T(t).from(r).select(i).range(n.offset,n.offset+n.limit-1);a=U(r,a,n.filters),n.orderBy&&(L(r,n.orderBy.column),a=a.order(n.orderBy.column,{ascending:n.orderBy.ascending}));let{data:o,error:s}=await a;if(s)throw Error(`Failed to read database records: ${E(s)}`);let c=Array.isArray(o)?o:[];return{columns:i.split(`,`),limit:n.limit,offset:n.offset,rows:B(c),success:!0,table:r}}async function Q(e,t){let n=C.parse(e),r=q(n),i=T(t);await g(n,r,t);let a=J({input:n,table:r,targetRows:n.operation===`update`||n.operation===`delete`?await K(i,r,n.filters??[]):[]}),o={input:n,targetIds:a.targetIds},s=M({action:`DATABASE ${n.operation}`,context:t,payload:o,preview:a,subject:r});if(s)return s;try{let e=await ee(n,r,i),s=t?.skipAudit?{auditLogged:!1}:await Y({context:t,input:o,preview:a,status:`success`,summary:String(a.summary),targetTables:[r],toolName:`execute_database_mutation`});return{affectedCount:e.length||a.affectedCount,auditLogged:s.auditLogged,...s.auditError?{auditError:s.auditError}:{},mutationExecuted:!0,operation:n.operation,sampleTargetIds:e.map(e=>G(e,F(r).primaryKey)).slice(0,10),success:!0,summary:a.summary,table:r}}catch(e){let i=E(e),s=t?.skipAudit?{auditLogged:!1}:await Y({context:t,errorMessage:i,input:o,preview:a,status:`failure`,summary:String(a.summary),targetTables:[r],toolName:`execute_database_mutation`});return{auditLogged:s.auditLogged,...s.auditError?{auditError:s.auditError}:{},message:`Database mutation failed: ${i}`,mutationExecuted:!1,operation:n.operation,success:!1,table:r}}}async function $(e,t){let n=w.parse(e),r=[];for(let e of n.actions){let n=q(e);await g(e,n,t);let i=e.operation===`update`||e.operation===`delete`?await K(T(t),n,e.filters??[]):[];r.push({input:e,preview:J({input:e,table:n,targetRows:i}),table:n})}let i=r.map(({preview:e})=>String(e.summary)),a={actionCount:r.length,actionSummaries:i,summary:n.summary||`Run ${r.length} confirmed database actions.`,tables:Array.from(new Set(r.map(e=>e.table)))},o=r.map(({input:e,preview:t,table:n})=>({input:e,table:n,targetIds:t.targetIds})),s=M({action:`DATABASE ACTION PLAN`,context:t,payload:o,preview:a,subject:`${r.length} actions`});if(s)return s;let c=[],l=!1;for(let[e,n]of r.entries()){let i=await Q(n.input,{...t,skipAudit:!0,skipConfirmation:!0});if(c.push(i),i&&typeof i==`object`&&i.mutationExecuted===!0&&(l=!0),!i||typeof i!=`object`||i.success===!1){let n=await Y({context:t,errorMessage:i&&typeof i==`object`&&typeof i.message==`string`?i.message:`Database action ${e+1} failed.`,input:o,preview:a,status:`failure`,summary:String(a.summary),targetTables:a.tables,toolName:`execute_database_action_plan`});return{actionCount:r.length,auditLogged:n.auditLogged,...n.auditError?{auditError:n.auditError}:{},failedActionIndex:e,message:i&&typeof i==`object`&&typeof i.message==`string`?i.message:`Database action ${e+1} failed.`,mutationExecuted:l,results:c,success:!1}}}let u=await Y({context:t,input:o,preview:a,status:`success`,summary:String(a.summary),targetTables:a.tables,toolName:`execute_database_action_plan`});return{actionCount:r.length,auditLogged:u.auditLogged,...u.auditError?{auditError:u.auditError}:{},mutationExecuted:l,results:c,success:!0,summary:n.summary??null}}function te(e){return{describe_database_schema:(0,n.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:e=>X(e),inputSchema:x,strict:!0}),execute_database_action_plan:(0,n.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=>$(t,e),inputSchema:w,strict:!0}),execute_database_mutation:(0,n.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:C,strict:!0}),read_database_records:(0,n.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:S,strict:!0})}}exports.createCortexDatabaseAgentTools=te,exports.describeDatabaseSchemaInputSchema=x,exports.executeDatabaseActionPlan=$,exports.executeDatabaseActionPlanInputSchema=w,exports.executeDatabaseMutation=Q,exports.executeDatabaseMutationInputSchema=C,exports.executeDescribeDatabaseSchema=X,exports.executeReadDatabaseRecords=Z,exports.readDatabaseRecordsInputSchema=S;
|