@sendinel/mcp-server 1.0.33 → 1.0.34

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.
@@ -307,6 +307,15 @@ export function registerCampaignSetTools(server) {
307
307
  const empty = set.campaigns.filter((c) => !set.steps.some((s) => s.campaign_id === c.id));
308
308
  if (empty.length)
309
309
  return j({ error: 'Some campaigns have no emails yet.', code: 'NO_EMAILS', campaigns: empty.map((c) => ({ id: c.id, name: c.name })) });
310
+ // An imported email whose wait wasn't in the source has no delay; it would never send (#3689).
311
+ const waitNotSet = set.steps.filter((s) => s.delay_days == null && s.delay_hours == null);
312
+ if (waitNotSet.length) {
313
+ return j({
314
+ error: 'Some emails have no wait set. Set how long to wait before each one, then try again.',
315
+ code: 'STEP_WAIT_NOT_SET',
316
+ emails: waitNotSet.map((s) => ({ campaign: set.campaigns.find((c) => c.id === s.campaign_id)?.name ?? s.campaign_id, email: s.step_order + 1, subject: s.subject })),
317
+ });
318
+ }
310
319
  const approvalParams = { campaign_ids: [...ids].sort(), content_hash: campaignSetContentHash(set.campaigns, set.steps) };
311
320
  const channelContext = currentChannelContext();
312
321
  const decision = assertChannelCanExecute('activate_campaigns', approvalParams, channelContext);
@@ -595,6 +595,22 @@ export function registerCampaignTools(server) {
595
595
  }, async ({ campaign_id, status, approval_id }) => {
596
596
  // Human approval required for activation
597
597
  if (status === 'active') {
598
+ // An imported email whose wait wasn't in the source has no delay; it would never send (#3689).
599
+ const { data: unsetSteps, error: stepsErr } = await db()
600
+ .from('campaign_steps')
601
+ .select('step_order, subject')
602
+ .eq('campaign_id', campaign_id)
603
+ .is('delay_days', null)
604
+ .is('delay_hours', null);
605
+ if (stepsErr)
606
+ return j({ error: `Could not check the campaign's emails: ${stepsErr.message}`, code: 'STEP_LOOKUP_FAILED' });
607
+ if (unsetSteps?.length) {
608
+ return j({
609
+ error: 'Some emails have no wait set. Set how long to wait before each one, then try again.',
610
+ code: 'STEP_WAIT_NOT_SET',
611
+ emails: unsetSteps.map((s) => ({ email: s.step_order + 1, subject: s.subject })),
612
+ });
613
+ }
598
614
  const approvalParams = { campaign_id, status };
599
615
  if (!approval_id) {
600
616
  const channelContext = currentChannelContext();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendinel/mcp-server",
3
- "version": "1.0.33",
3
+ "version": "1.0.34",
4
4
  "description": "AI-controlled email operations control plane for campaigns, contacts, segments, analytics, and multi-provider sending via MCP.",
5
5
  "mcpName": "ai.sendinel/mcp-server",
6
6
  "type": "module",