@sendinel/mcp-server 1.0.146 → 1.0.148
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/build/lib/action-approvals.js +3 -1
- package/build/lib/db-error.d.ts +39 -6
- package/build/lib/db-error.js +221 -11
- package/build/server.js +5 -3
- package/build/tools/ab-testing.js +4 -3
- package/build/tools/advisor.js +2 -2
- package/build/tools/ai-work.js +14 -13
- package/build/tools/analytics.js +33 -32
- package/build/tools/approvals.js +3 -1
- package/build/tools/automations.js +12 -11
- package/build/tools/brand-kit.js +4 -3
- package/build/tools/campaign-sets.js +11 -10
- package/build/tools/campaigns.js +81 -79
- package/build/tools/compound.js +7 -6
- package/build/tools/connector.js +4 -3
- package/build/tools/contacts.js +44 -45
- package/build/tools/content.js +16 -16
- package/build/tools/convert-imported.js +8 -7
- package/build/tools/data-proposals.js +8 -7
- package/build/tools/data.js +39 -38
- package/build/tools/delivery-ops.js +32 -32
- package/build/tools/drafts.js +10 -9
- package/build/tools/forms.js +5 -4
- package/build/tools/gdpr.js +10 -9
- package/build/tools/landing-pages.js +3 -3
- package/build/tools/lists.js +21 -20
- package/build/tools/newsletters.js +26 -25
- package/build/tools/org.js +26 -23
- package/build/tools/segments.js +4 -5
- package/build/tools/short-links.js +7 -6
- package/build/tools/signatures.js +10 -9
- package/build/tools/sites.js +9 -8
- package/build/tools/sms.js +14 -13
- package/build/tools/social-posts.js +20 -19
- package/build/tools/social-replies.js +7 -6
- package/build/tools/surveys.js +10 -9
- package/build/tools/templates.js +14 -13
- package/build/tools/warmup.js +5 -4
- package/build/tools/webhooks.js +5 -4
- package/package.json +1 -1
- package/build/lib/db-errors.d.ts +0 -12
- package/build/lib/db-errors.js +0 -20
|
@@ -7,6 +7,7 @@ import { validateTemplate } from '../lib/voice.js';
|
|
|
7
7
|
import { logAudit } from '../audit.js';
|
|
8
8
|
import { eventKeysFromHistory, contactPropertyKeys } from '../lib/content-sources.js';
|
|
9
9
|
import { loadSet, previewOf, writeCampaignDrafts } from './campaign-sets.js';
|
|
10
|
+
import { dbToolError } from '../lib/db-error.js';
|
|
10
11
|
/**
|
|
11
12
|
* convert_imported_campaigns (#3689): turns campaigns imported from another platform (Customer.io
|
|
12
13
|
* first) into new Sendinel drafts that can send. Call it without create to preview: converted
|
|
@@ -44,7 +45,7 @@ function reviewView(plan) {
|
|
|
44
45
|
original_subject: email.original_subject,
|
|
45
46
|
subject: email.subject,
|
|
46
47
|
text: email.preview_text,
|
|
47
|
-
check_these: email.flags.map((flag) => ({ kind: flag.kind, message: flag.
|
|
48
|
+
check_these: email.flags.map((flag) => ({ kind: flag.kind, message: dbToolError(flag).error, ...(flag.excerpt ? { where: flag.excerpt } : {}) })),
|
|
48
49
|
})),
|
|
49
50
|
...(plan.blocking.length ? { must_fix: plan.blocking } : {}),
|
|
50
51
|
...(plan.notes.length ? { notes: plan.notes } : {}),
|
|
@@ -70,7 +71,7 @@ export function registerConvertImportedTools(server) {
|
|
|
70
71
|
.eq('project_id', projectId)
|
|
71
72
|
.in('id', ids);
|
|
72
73
|
if (sourceErr)
|
|
73
|
-
return j({
|
|
74
|
+
return j({ ...dbToolError(sourceErr), code: 'CAMPAIGN_LOOKUP_FAILED' });
|
|
74
75
|
const byId = new Map((sources ?? []).map((c) => [c.id, c]));
|
|
75
76
|
const missing = ids.filter((id) => !byId.has(id));
|
|
76
77
|
if (missing.length)
|
|
@@ -83,7 +84,7 @@ export function registerConvertImportedTools(server) {
|
|
|
83
84
|
.select('campaign_id, step_order, subject, body_html, body_text, delay_days, delay_hours')
|
|
84
85
|
.in('campaign_id', ids);
|
|
85
86
|
if (stepErr)
|
|
86
|
-
return j({
|
|
87
|
+
return j({ ...dbToolError(stepErr), code: 'STEP_LOOKUP_FAILED' });
|
|
87
88
|
const steps = (stepRows ?? []);
|
|
88
89
|
// Event data seen in history, per trigger. A failed lookup is reported, never treated as "none".
|
|
89
90
|
const historyNotes = [];
|
|
@@ -110,7 +111,7 @@ export function registerConvertImportedTools(server) {
|
|
|
110
111
|
.eq('project_id', projectId)
|
|
111
112
|
.in('metadata->>converted_from', ids);
|
|
112
113
|
if (existingErr)
|
|
113
|
-
return j({
|
|
114
|
+
return j({ ...dbToolError(existingErr), code: 'CAMPAIGN_LOOKUP_FAILED' });
|
|
114
115
|
const earlier = (existing ?? []);
|
|
115
116
|
plans.forEach((plan) => {
|
|
116
117
|
const twin = earlier.find((e) => e.metadata?.converted_from === plan.source_campaign_id && e.name === plan.name);
|
|
@@ -138,7 +139,7 @@ export function registerConvertImportedTools(server) {
|
|
|
138
139
|
// Sender: the given one, the imports' own, or the only one. Never guessed between several.
|
|
139
140
|
const { data: sites, error: sitesErr } = await db().from('sites').select('id, name, from_email, unsub_link_enabled').eq('project_id', projectId);
|
|
140
141
|
if (sitesErr)
|
|
141
|
-
return j({
|
|
142
|
+
return j({ ...dbToolError(sitesErr), code: 'SITE_LOOKUP_FAILED' });
|
|
142
143
|
const importSites = [...new Set(ids.map((id) => byId.get(id).site_id).filter(Boolean))];
|
|
143
144
|
const pick = site_id ?? (importSites.length === 1 ? importSites[0] : sites?.length === 1 ? sites[0].id : null);
|
|
144
145
|
const site = (sites ?? []).find((s) => s.id === pick);
|
|
@@ -170,7 +171,7 @@ export function registerConvertImportedTools(server) {
|
|
|
170
171
|
metadata: {
|
|
171
172
|
converted_from: plan.source_campaign_id,
|
|
172
173
|
converted_from_name: plan.source_name,
|
|
173
|
-
review_flags: plan.emails.flatMap((email) => email.flags.map((flag) => ({ email: email.email, kind: flag.kind, message: flag.
|
|
174
|
+
review_flags: plan.emails.flatMap((email) => email.flags.map((flag) => ({ email: email.email, kind: flag.kind, message: dbToolError(flag).error, ...(flag.excerpt ? { excerpt: flag.excerpt } : {}) }))),
|
|
174
175
|
},
|
|
175
176
|
emails: plan.emails.map((email) => ({
|
|
176
177
|
subject: email.subject,
|
|
@@ -200,7 +201,7 @@ export function registerConvertImportedTools(server) {
|
|
|
200
201
|
preview = previewOf(loaded.campaigns, loaded.steps);
|
|
201
202
|
}
|
|
202
203
|
catch (error) {
|
|
203
|
-
return j({ campaign_set_id: setId, campaign_ids: createdIds, status: 'draft', warning: `Created, but the preview could not be read back: ${error instanceof Error ? error.
|
|
204
|
+
return j({ campaign_set_id: setId, campaign_ids: createdIds, status: 'draft', warning: `Created, but the preview could not be read back: ${error instanceof Error ? dbToolError(error).error : String(error)}` });
|
|
204
205
|
}
|
|
205
206
|
return j({
|
|
206
207
|
campaign_set_id: setId,
|
|
@@ -3,6 +3,7 @@ import { z } from 'zod';
|
|
|
3
3
|
import { db } from '../db.js';
|
|
4
4
|
import { getProjectId } from '../project.js';
|
|
5
5
|
import { getAnthropicModelId } from '../anthropic-model.js';
|
|
6
|
+
import { dbToolError } from '../lib/db-error.js';
|
|
6
7
|
const txt = (text) => ({ content: [{ type: 'text', text }] });
|
|
7
8
|
const j = (data) => txt(JSON.stringify(data, null, 2));
|
|
8
9
|
async function engagementSnapshot(projectId) {
|
|
@@ -47,7 +48,7 @@ export function registerDataProposalTools(server) {
|
|
|
47
48
|
.eq('id', projectId)
|
|
48
49
|
.maybeSingle();
|
|
49
50
|
if (projectError)
|
|
50
|
-
return txt(`Error: ${projectError.
|
|
51
|
+
return txt(`Error: ${dbToolError(projectError).error}`);
|
|
51
52
|
if (!project)
|
|
52
53
|
return txt('Project not found.');
|
|
53
54
|
const snapshot = await engagementSnapshot(projectId);
|
|
@@ -76,7 +77,7 @@ export function registerDataProposalTools(server) {
|
|
|
76
77
|
.select('*')
|
|
77
78
|
.single();
|
|
78
79
|
if (error)
|
|
79
|
-
return txt(`Error: ${error.
|
|
80
|
+
return txt(`Error: ${dbToolError(error).error}`);
|
|
80
81
|
return j({ proposal: data });
|
|
81
82
|
});
|
|
82
83
|
server.registerTool('list_data_proposals', {
|
|
@@ -103,7 +104,7 @@ export function registerDataProposalTools(server) {
|
|
|
103
104
|
query = query.eq('status', status);
|
|
104
105
|
const { data, error } = await query;
|
|
105
106
|
if (error)
|
|
106
|
-
return txt(`Error: ${error.
|
|
107
|
+
return txt(`Error: ${dbToolError(error).error}`);
|
|
107
108
|
return j({ proposals: data ?? [] });
|
|
108
109
|
});
|
|
109
110
|
server.registerTool('approve_data_proposal', {
|
|
@@ -127,7 +128,7 @@ export function registerDataProposalTools(server) {
|
|
|
127
128
|
.eq('project_id', projectId)
|
|
128
129
|
.maybeSingle();
|
|
129
130
|
if (proposalError)
|
|
130
|
-
return txt(`Error: ${proposalError.
|
|
131
|
+
return txt(`Error: ${dbToolError(proposalError).error}`);
|
|
131
132
|
if (!proposal)
|
|
132
133
|
return txt('Proposal not found.');
|
|
133
134
|
if (!['pending', 'approved'].includes(proposal.status))
|
|
@@ -141,7 +142,7 @@ export function registerDataProposalTools(server) {
|
|
|
141
142
|
.limit(1)
|
|
142
143
|
.maybeSingle();
|
|
143
144
|
if (siteError)
|
|
144
|
-
return txt(`Error: ${siteError.
|
|
145
|
+
return txt(`Error: ${dbToolError(siteError).error}`);
|
|
145
146
|
if (!site)
|
|
146
147
|
return txt('No active site available for draft conversion.');
|
|
147
148
|
const { data: draft, error: draftError } = await db()
|
|
@@ -158,7 +159,7 @@ export function registerDataProposalTools(server) {
|
|
|
158
159
|
.select('id')
|
|
159
160
|
.single();
|
|
160
161
|
if (draftError)
|
|
161
|
-
return txt(`Error: ${draftError.
|
|
162
|
+
return txt(`Error: ${dbToolError(draftError).error}`);
|
|
162
163
|
const { data: updated, error: updateError } = await db()
|
|
163
164
|
.from('data_proposals')
|
|
164
165
|
.update({
|
|
@@ -171,7 +172,7 @@ export function registerDataProposalTools(server) {
|
|
|
171
172
|
.select('*')
|
|
172
173
|
.single();
|
|
173
174
|
if (updateError)
|
|
174
|
-
return txt(`Error: ${updateError.
|
|
175
|
+
return txt(`Error: ${dbToolError(updateError).error}`);
|
|
175
176
|
return j({ proposal: updated, draft_id: draft.id });
|
|
176
177
|
});
|
|
177
178
|
}
|
package/build/tools/data.js
CHANGED
|
@@ -7,6 +7,7 @@ import { normalizeActiveCampaignAccountUrl } from '../lib/url-validation.js';
|
|
|
7
7
|
import { assertChannelCanExecute, checkApproval, currentChannelContext, requestApproval, withApproval } from '../lib/action-approvals.js';
|
|
8
8
|
import { getProjectId } from '../project.js';
|
|
9
9
|
import { logAudit } from '../audit.js';
|
|
10
|
+
import { dbToolError } from '../lib/db-error.js';
|
|
10
11
|
const j = (data) => ({ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] });
|
|
11
12
|
function generateApiKey() {
|
|
12
13
|
const secret = `snk_${randomBytes(32).toString('hex')}`;
|
|
@@ -263,14 +264,14 @@ export function registerDataTools(server) {
|
|
|
263
264
|
query = query.eq('is_active', true);
|
|
264
265
|
const { data, error } = await query;
|
|
265
266
|
if (error)
|
|
266
|
-
return j(
|
|
267
|
+
return j(dbToolError(error));
|
|
267
268
|
return j({
|
|
268
269
|
platforms: CONNECTED_PLATFORMS.filter((platform) => platform !== 'kit'),
|
|
269
270
|
connections: (data ?? []).map(sanitizeConnection),
|
|
270
271
|
});
|
|
271
272
|
}
|
|
272
273
|
catch (error) {
|
|
273
|
-
return j({ error: error instanceof Error ? error.
|
|
274
|
+
return j({ error: error instanceof Error ? dbToolError(error).error : 'Failed to list connected platforms' });
|
|
274
275
|
}
|
|
275
276
|
});
|
|
276
277
|
server.registerTool('list_provider_credentials', {
|
|
@@ -309,9 +310,9 @@ export function registerDataTools(server) {
|
|
|
309
310
|
.limit(50);
|
|
310
311
|
const [platformResult, importResult] = await Promise.all([platformQuery, importQuery]);
|
|
311
312
|
if (platformResult.error)
|
|
312
|
-
return j(
|
|
313
|
+
return j(dbToolError(platformResult.error));
|
|
313
314
|
if (importResult.error)
|
|
314
|
-
return j(
|
|
315
|
+
return j(dbToolError(importResult.error));
|
|
315
316
|
const mapRow = (row, source) => {
|
|
316
317
|
let credential;
|
|
317
318
|
try {
|
|
@@ -351,7 +352,7 @@ export function registerDataTools(server) {
|
|
|
351
352
|
return j({ credentials: [...platformCredentials, ...importCredentials] });
|
|
352
353
|
}
|
|
353
354
|
catch (error) {
|
|
354
|
-
return j({ error: error instanceof Error ? error.
|
|
355
|
+
return j({ error: error instanceof Error ? dbToolError(error).error : 'Failed to list provider credentials' });
|
|
355
356
|
}
|
|
356
357
|
});
|
|
357
358
|
server.registerTool('delete_provider_credential', {
|
|
@@ -389,7 +390,7 @@ export function registerDataTools(server) {
|
|
|
389
390
|
.eq('project_id', context.projectId)
|
|
390
391
|
.maybeSingle();
|
|
391
392
|
if (credentialErr)
|
|
392
|
-
return j(
|
|
393
|
+
return j(dbToolError(credentialErr));
|
|
393
394
|
if (!credential)
|
|
394
395
|
return j({ error: 'Credential not found' });
|
|
395
396
|
const provider = parsed.source === 'platform' ? credential.platform : credential.provider;
|
|
@@ -449,7 +450,7 @@ export function registerDataTools(server) {
|
|
|
449
450
|
.select('id, platform')
|
|
450
451
|
.maybeSingle();
|
|
451
452
|
if (error)
|
|
452
|
-
return j(
|
|
453
|
+
return j(dbToolError(error));
|
|
453
454
|
if (!data)
|
|
454
455
|
return j({ error: 'Credential not found' });
|
|
455
456
|
await logAudit({
|
|
@@ -471,7 +472,7 @@ export function registerDataTools(server) {
|
|
|
471
472
|
.select('id, provider')
|
|
472
473
|
.maybeSingle();
|
|
473
474
|
if (error)
|
|
474
|
-
return j(
|
|
475
|
+
return j(dbToolError(error));
|
|
475
476
|
if (!data)
|
|
476
477
|
return j({ error: 'Credential not found' });
|
|
477
478
|
await logAudit({
|
|
@@ -483,7 +484,7 @@ export function registerDataTools(server) {
|
|
|
483
484
|
return j({ deleted: true, id: credential_id, source: 'import', provider: data.provider });
|
|
484
485
|
}
|
|
485
486
|
catch (error) {
|
|
486
|
-
return j({ error: error instanceof Error ? error.
|
|
487
|
+
return j({ error: error instanceof Error ? dbToolError(error).error : 'Failed to delete provider credential' });
|
|
487
488
|
}
|
|
488
489
|
});
|
|
489
490
|
server.registerTool('connect_platform', {
|
|
@@ -535,7 +536,7 @@ export function registerDataTools(server) {
|
|
|
535
536
|
.select('id, org_id, project_id, platform, display_name, config, status, is_active, last_synced_at, last_error, created_at, updated_at')
|
|
536
537
|
.single();
|
|
537
538
|
if (error)
|
|
538
|
-
return j(
|
|
539
|
+
return j(dbToolError(error));
|
|
539
540
|
await logAudit({
|
|
540
541
|
action: 'platform_connection.connected',
|
|
541
542
|
resourceType: 'platform_connection',
|
|
@@ -549,7 +550,7 @@ export function registerDataTools(server) {
|
|
|
549
550
|
});
|
|
550
551
|
}
|
|
551
552
|
catch (error) {
|
|
552
|
-
return j({ error: error instanceof Error ? error.
|
|
553
|
+
return j({ error: error instanceof Error ? dbToolError(error).error : 'Failed to connect platform' });
|
|
553
554
|
}
|
|
554
555
|
});
|
|
555
556
|
server.registerTool('disconnect_platform', {
|
|
@@ -585,7 +586,7 @@ export function registerDataTools(server) {
|
|
|
585
586
|
query = query.eq('platform', normalizePlatform(platform));
|
|
586
587
|
const { data, error } = await query.select('id, platform');
|
|
587
588
|
if (error)
|
|
588
|
-
return j(
|
|
589
|
+
return j(dbToolError(error));
|
|
589
590
|
await logAudit({
|
|
590
591
|
action: 'platform_connection.disconnected',
|
|
591
592
|
resourceType: 'platform_connection',
|
|
@@ -595,7 +596,7 @@ export function registerDataTools(server) {
|
|
|
595
596
|
return j({ disconnected: data?.length ?? 0, connections: data ?? [] });
|
|
596
597
|
}
|
|
597
598
|
catch (error) {
|
|
598
|
-
return j({ error: error instanceof Error ? error.
|
|
599
|
+
return j({ error: error instanceof Error ? dbToolError(error).error : 'Failed to disconnect platform' });
|
|
599
600
|
}
|
|
600
601
|
}));
|
|
601
602
|
server.registerTool('list_platform_events', {
|
|
@@ -628,11 +629,11 @@ export function registerDataTools(server) {
|
|
|
628
629
|
query = query.eq('platform', normalizePlatform(platform));
|
|
629
630
|
const { data, error } = await query;
|
|
630
631
|
if (error)
|
|
631
|
-
return j(
|
|
632
|
+
return j(dbToolError(error));
|
|
632
633
|
return j({ events: data ?? [] });
|
|
633
634
|
}
|
|
634
635
|
catch (error) {
|
|
635
|
-
return j({ error: error instanceof Error ? error.
|
|
636
|
+
return j({ error: error instanceof Error ? dbToolError(error).error : 'Failed to list platform events' });
|
|
636
637
|
}
|
|
637
638
|
});
|
|
638
639
|
server.registerTool('configure_platform_trigger', {
|
|
@@ -673,7 +674,7 @@ export function registerDataTools(server) {
|
|
|
673
674
|
.eq('is_active', true)
|
|
674
675
|
.maybeSingle();
|
|
675
676
|
if (connectionError)
|
|
676
|
-
return j(
|
|
677
|
+
return j(dbToolError(connectionError));
|
|
677
678
|
if (!connection)
|
|
678
679
|
return j({ error: 'active platform connection not found' });
|
|
679
680
|
const currentConfig = connection.config ?? connection.meta ?? {};
|
|
@@ -692,7 +693,7 @@ export function registerDataTools(server) {
|
|
|
692
693
|
.select('id, platform, display_name, config, status, is_active, last_synced_at, updated_at')
|
|
693
694
|
.single();
|
|
694
695
|
if (error)
|
|
695
|
-
return j(
|
|
696
|
+
return j(dbToolError(error));
|
|
696
697
|
await logAudit({
|
|
697
698
|
action: 'platform_trigger.configured',
|
|
698
699
|
resourceType: 'platform_connection',
|
|
@@ -702,7 +703,7 @@ export function registerDataTools(server) {
|
|
|
702
703
|
return j({ connection: sanitizeConnection(data), trigger });
|
|
703
704
|
}
|
|
704
705
|
catch (error) {
|
|
705
|
-
return j({ error: error instanceof Error ? error.
|
|
706
|
+
return j({ error: error instanceof Error ? dbToolError(error).error : 'Failed to configure platform trigger' });
|
|
706
707
|
}
|
|
707
708
|
});
|
|
708
709
|
server.registerTool('list_custom_webhooks', {
|
|
@@ -734,7 +735,7 @@ export function registerDataTools(server) {
|
|
|
734
735
|
query = query.eq('is_active', true);
|
|
735
736
|
const { data, error } = await query;
|
|
736
737
|
if (error)
|
|
737
|
-
return j(
|
|
738
|
+
return j(dbToolError(error));
|
|
738
739
|
return j({
|
|
739
740
|
connections: (data ?? []).map((connection) => ({
|
|
740
741
|
id: connection.id,
|
|
@@ -749,7 +750,7 @@ export function registerDataTools(server) {
|
|
|
749
750
|
});
|
|
750
751
|
}
|
|
751
752
|
catch (error) {
|
|
752
|
-
return j({ error: error instanceof Error ? error.
|
|
753
|
+
return j({ error: error instanceof Error ? dbToolError(error).error : 'Failed to list custom webhooks' });
|
|
753
754
|
}
|
|
754
755
|
});
|
|
755
756
|
server.registerTool('create_custom_webhook', {
|
|
@@ -798,7 +799,7 @@ export function registerDataTools(server) {
|
|
|
798
799
|
.select('id')
|
|
799
800
|
.single();
|
|
800
801
|
if (error || !data)
|
|
801
|
-
return j({ error: error
|
|
802
|
+
return j({ error: (error ? dbToolError(error).error : undefined) ?? 'Failed to create custom webhook' });
|
|
802
803
|
const endpointUrl = customWebhookEndpointUrl(data.id);
|
|
803
804
|
await client
|
|
804
805
|
.schema('email')
|
|
@@ -818,7 +819,7 @@ export function registerDataTools(server) {
|
|
|
818
819
|
});
|
|
819
820
|
}
|
|
820
821
|
catch (error) {
|
|
821
|
-
return j({ error: error instanceof Error ? error.
|
|
822
|
+
return j({ error: error instanceof Error ? dbToolError(error).error : 'Failed to create custom webhook' });
|
|
822
823
|
}
|
|
823
824
|
});
|
|
824
825
|
server.registerTool('rotate_custom_webhook_secret', {
|
|
@@ -849,7 +850,7 @@ export function registerDataTools(server) {
|
|
|
849
850
|
.eq('is_active', true)
|
|
850
851
|
.maybeSingle();
|
|
851
852
|
if (lookupError)
|
|
852
|
-
return j(
|
|
853
|
+
return j(dbToolError(lookupError));
|
|
853
854
|
if (!connection)
|
|
854
855
|
return j({ error: 'Custom webhook not found' });
|
|
855
856
|
if (!confirmed) {
|
|
@@ -903,7 +904,7 @@ export function registerDataTools(server) {
|
|
|
903
904
|
.select('id')
|
|
904
905
|
.maybeSingle();
|
|
905
906
|
if (error)
|
|
906
|
-
return j(
|
|
907
|
+
return j(dbToolError(error));
|
|
907
908
|
if (!updated)
|
|
908
909
|
return j({ error: 'Custom webhook is no longer active' });
|
|
909
910
|
await logAudit({
|
|
@@ -919,7 +920,7 @@ export function registerDataTools(server) {
|
|
|
919
920
|
});
|
|
920
921
|
}
|
|
921
922
|
catch (error) {
|
|
922
|
-
return j({ error: error instanceof Error ? error.
|
|
923
|
+
return j({ error: error instanceof Error ? dbToolError(error).error : 'Failed to rotate custom webhook secret' });
|
|
923
924
|
}
|
|
924
925
|
});
|
|
925
926
|
server.registerTool('list_import_history', {
|
|
@@ -939,7 +940,7 @@ export function registerDataTools(server) {
|
|
|
939
940
|
.order('created_at', { ascending: false })
|
|
940
941
|
.limit(limit);
|
|
941
942
|
if (error)
|
|
942
|
-
return j(
|
|
943
|
+
return j(dbToolError(error));
|
|
943
944
|
return j({
|
|
944
945
|
imports: (data ?? []).map((row) => ({
|
|
945
946
|
...row,
|
|
@@ -966,7 +967,7 @@ export function registerDataTools(server) {
|
|
|
966
967
|
.is('revoked_at', null)
|
|
967
968
|
.order('created_at', { ascending: false });
|
|
968
969
|
if (error)
|
|
969
|
-
return j(
|
|
970
|
+
return j(dbToolError(error));
|
|
970
971
|
return j({ keys: data ?? [] });
|
|
971
972
|
});
|
|
972
973
|
server.registerTool('create_api_key', {
|
|
@@ -997,7 +998,7 @@ export function registerDataTools(server) {
|
|
|
997
998
|
.select('id, name, slug')
|
|
998
999
|
.single();
|
|
999
1000
|
if (error)
|
|
1000
|
-
return j(
|
|
1001
|
+
return j(dbToolError(error));
|
|
1001
1002
|
return j({ key_id: data.id, name: data.name, slug: data.slug, secret });
|
|
1002
1003
|
}));
|
|
1003
1004
|
server.registerTool('revoke_api_key', {
|
|
@@ -1013,7 +1014,7 @@ export function registerDataTools(server) {
|
|
|
1013
1014
|
}, withApproval('revoke_api_key', async ({ key_id }) => {
|
|
1014
1015
|
const { error } = await db().from('api_keys').update({ revoked_at: new Date().toISOString() }).eq('project_id', getProjectId()).eq('id', key_id);
|
|
1015
1016
|
if (error)
|
|
1016
|
-
return j(
|
|
1017
|
+
return j(dbToolError(error));
|
|
1017
1018
|
return j({ revoked: true });
|
|
1018
1019
|
}));
|
|
1019
1020
|
server.registerTool('migrate_campaigns_from', {
|
|
@@ -1042,7 +1043,7 @@ export function registerDataTools(server) {
|
|
|
1042
1043
|
.eq('id', projectId)
|
|
1043
1044
|
.maybeSingle();
|
|
1044
1045
|
if (projectError)
|
|
1045
|
-
return j(
|
|
1046
|
+
return j(dbToolError(projectError));
|
|
1046
1047
|
if (!project?.org_id)
|
|
1047
1048
|
return j({ error: 'project not found' });
|
|
1048
1049
|
let normalizedAccountUrl = account_url;
|
|
@@ -1051,7 +1052,7 @@ export function registerDataTools(server) {
|
|
|
1051
1052
|
normalizedAccountUrl = normalizeActiveCampaignAccountUrl(account_url ?? '');
|
|
1052
1053
|
}
|
|
1053
1054
|
catch (error) {
|
|
1054
|
-
return j({ error: error instanceof Error ? error.
|
|
1055
|
+
return j({ error: error instanceof Error ? dbToolError(error).error : 'Invalid ActiveCampaign account URL' });
|
|
1055
1056
|
}
|
|
1056
1057
|
}
|
|
1057
1058
|
const credentials = { api_key: oauth_token, account_url: normalizedAccountUrl };
|
|
@@ -1073,7 +1074,7 @@ export function registerDataTools(server) {
|
|
|
1073
1074
|
.select('id')
|
|
1074
1075
|
.single();
|
|
1075
1076
|
if (error)
|
|
1076
|
-
return j(
|
|
1077
|
+
return j(dbToolError(error));
|
|
1077
1078
|
return j({
|
|
1078
1079
|
job_id: data.id,
|
|
1079
1080
|
status: 'pending',
|
|
@@ -1116,7 +1117,7 @@ export function registerDataTools(server) {
|
|
|
1116
1117
|
.eq('is_active', true)
|
|
1117
1118
|
.maybeSingle();
|
|
1118
1119
|
if (connectionError)
|
|
1119
|
-
return j(
|
|
1120
|
+
return j(dbToolError(connectionError));
|
|
1120
1121
|
if (!connection)
|
|
1121
1122
|
return j({ error: 'platform connection not found' });
|
|
1122
1123
|
if (!MIGRATION_PROVIDERS.includes(connection.platform))
|
|
@@ -1142,7 +1143,7 @@ export function registerDataTools(server) {
|
|
|
1142
1143
|
.select('id')
|
|
1143
1144
|
.single();
|
|
1144
1145
|
if (error)
|
|
1145
|
-
return j(
|
|
1146
|
+
return j(dbToolError(error));
|
|
1146
1147
|
await client.schema('email').from('platform_connections').update({ last_synced_at: new Date().toISOString() }).eq('id', connection_id);
|
|
1147
1148
|
return j({ job_id: data.id, status: 'pending', connection_id, provider: connection.platform });
|
|
1148
1149
|
});
|
|
@@ -1165,7 +1166,7 @@ export function registerDataTools(server) {
|
|
|
1165
1166
|
query = query.eq('read', false);
|
|
1166
1167
|
const { data, error } = await query;
|
|
1167
1168
|
if (error)
|
|
1168
|
-
return j(
|
|
1169
|
+
return j(dbToolError(error));
|
|
1169
1170
|
return j({ notifications: (data ?? []).map((row) => ({ ...row, read: row.read === true, read_at: null })) });
|
|
1170
1171
|
});
|
|
1171
1172
|
server.registerTool('mark_notifications_read', {
|
|
@@ -1184,7 +1185,7 @@ export function registerDataTools(server) {
|
|
|
1184
1185
|
query = query.in('id', ids);
|
|
1185
1186
|
const { data, error } = await query.select('id');
|
|
1186
1187
|
if (error)
|
|
1187
|
-
return j(
|
|
1188
|
+
return j(dbToolError(error));
|
|
1188
1189
|
return j({ updated: data?.length ?? 0 });
|
|
1189
1190
|
});
|
|
1190
1191
|
server.registerTool('tenant_export_full', {
|
|
@@ -1278,10 +1279,10 @@ export function registerDataTools(server) {
|
|
|
1278
1279
|
upload = await client.storage.from(bucket).upload(path, createZip(files), { contentType: 'application/zip', upsert: true });
|
|
1279
1280
|
}
|
|
1280
1281
|
if (upload.error)
|
|
1281
|
-
return j(
|
|
1282
|
+
return j(dbToolError(upload.error));
|
|
1282
1283
|
const { data, error } = await client.storage.from(bucket).createSignedUrl(path, 24 * 3600);
|
|
1283
1284
|
if (error)
|
|
1284
|
-
return j(
|
|
1285
|
+
return j(dbToolError(error));
|
|
1285
1286
|
return j({
|
|
1286
1287
|
download_url: data.signedUrl,
|
|
1287
1288
|
expires_at: new Date(Date.now() + 24 * 3600 * 1000).toISOString(),
|