@sellable/mcp 0.1.517 → 0.1.519

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.
@@ -206,6 +206,7 @@ export type SelectPromisingPostsInput = {
206
206
  scrapePlanMode?: "all-selected" | "capacity-target";
207
207
  targetEngagerCount?: number;
208
208
  maxPostsToScrape?: number;
209
+ workspaceId?: string;
209
210
  };
210
211
  export type SetHeadlineICPCriteriaInput = {
211
212
  campaignOfferId: string;
@@ -4648,6 +4648,15 @@ export function getProviderPrompt(input) {
4648
4648
  }
4649
4649
  export async function selectPromisingPosts(input) {
4650
4650
  const api = getApi();
4651
+ const workspaceId = normalizeExplicitWorkspaceId(input.workspaceId);
4652
+ const requestOptions = workspaceRequestOptions(workspaceId);
4653
+ const apiGet = (path) => requestOptions ? api.get(path, requestOptions) : api.get(path);
4654
+ const apiPatch = (path, body) => requestOptions
4655
+ ? api.patch(path, body, requestOptions)
4656
+ : api.patch(path, body);
4657
+ const apiPut = (path, body) => requestOptions
4658
+ ? api.put(path, body, requestOptions)
4659
+ : api.put(path, body);
4651
4660
  const { campaignOfferId, selections, headlineICPCriteria, currentStep, selectionMode, mode, scrapePlanMode, targetEngagerCount, maxPostsToScrape, } = input;
4652
4661
  const effectiveMode = selectionMode ?? mode ?? "replace";
4653
4662
  const effectiveScrapePlanMode = scrapePlanMode ??
@@ -4667,14 +4676,14 @@ export async function selectPromisingPosts(input) {
4667
4676
  const postIds = selections.map((s) => s.postId);
4668
4677
  let unselectedIds = [];
4669
4678
  if (effectiveMode === "replace") {
4670
- const existing = await api.get(`/api/v3/campaigns/${campaignOfferId}/signal-discovery/posts?selected=true`);
4679
+ const existing = await apiGet(`/api/v3/campaigns/${campaignOfferId}/signal-discovery/posts?selected=true`);
4671
4680
  const existingIds = existing?.posts
4672
4681
  ?.map((post) => post.id)
4673
4682
  .filter((id) => Boolean(id)) ?? [];
4674
4683
  const selectedSet = new Set(postIds);
4675
4684
  unselectedIds = existingIds.filter((id) => !selectedSet.has(id));
4676
4685
  }
4677
- const selectionResult = await api.patch(`/api/v3/campaigns/${campaignOfferId}/signal-discovery/posts`, {
4686
+ const selectionResult = await apiPatch(`/api/v3/campaigns/${campaignOfferId}/signal-discovery/posts`, {
4678
4687
  selectedIds: postIds,
4679
4688
  unselectedIds,
4680
4689
  headlineICPCriteria,
@@ -4693,7 +4702,7 @@ export async function selectPromisingPosts(input) {
4693
4702
  let recommendedPostCount = selectionResult.selectedCount;
4694
4703
  let recommendationTargetEngagerCount = null;
4695
4704
  try {
4696
- const tabsResponse = await api.get(`/api/v3/campaigns/${campaignOfferId}/signal-discovery/tabs`);
4705
+ const tabsResponse = await apiGet(`/api/v3/campaigns/${campaignOfferId}/signal-discovery/tabs`);
4697
4706
  const reasonsByPostId = new Map(selections.map((selection) => [selection.postId, selection.reason]));
4698
4707
  const selectedByUrl = new Map();
4699
4708
  for (const tab of tabsResponse.tabs ?? []) {
@@ -4750,7 +4759,7 @@ Approval card should say:
4750
4759
  }
4751
4760
  const selectionCurrentStep = currentStep === null ? undefined : (currentStep ?? "signal-discovery");
4752
4761
  if (selectionCurrentStep) {
4753
- await api.put(`/api/v2/campaign-offers/${campaignOfferId}`, {
4762
+ await apiPut(`/api/v2/campaign-offers/${campaignOfferId}`, {
4754
4763
  currentStep: selectionCurrentStep,
4755
4764
  watchNarration: buildSelectedPostApprovalWatchNarration(selectionResult.selectedCount, recommendedPostCount, recommendationTargetEngagerCount),
4756
4765
  });
@@ -33,6 +33,10 @@ export type UserAddedRowsLimitPayload = {
33
33
  attemptedRows?: number;
34
34
  remainingRows?: number;
35
35
  };
36
+ export type SourceImportInProgressPayload = {
37
+ error?: string;
38
+ jobId?: string | null;
39
+ };
36
40
  export type PrepareRowSelector = {
37
41
  type: "needsEnrichment";
38
42
  limit?: number;
@@ -119,6 +123,7 @@ export declare function stringArray(value: unknown): string[];
119
123
  export declare function prepareRowSelectorValue(value: unknown): PrepareRowSelector | undefined;
120
124
  export declare function uniqueStrings(values: Array<string | null | undefined>): string[];
121
125
  export declare function userAddedRowsLimitPayloadFromError(error: unknown): UserAddedRowsLimitPayload | null;
126
+ export declare function sourceImportInProgressPayloadFromError(error: unknown): SourceImportInProgressPayload | null;
122
127
  export declare function paidRefreshActionFrom(value: unknown): PaidInmailRefreshAction | null;
123
128
  export declare function collectPaidInmailRefreshActions(plan: unknown): PaidInmailRefreshAction[];
124
129
  export declare function firstGlobalAction(plan: unknown): Record<string, unknown> | null;
@@ -85,6 +85,44 @@ export function userAddedRowsLimitPayloadFromError(error) {
85
85
  return null;
86
86
  }
87
87
  }
88
+ function apiErrorStatus(error) {
89
+ if (error instanceof SellableApiError)
90
+ return error.status;
91
+ const record = recordValue(error);
92
+ const status = record?.status;
93
+ return typeof status === "number" && Number.isFinite(status) ? status : null;
94
+ }
95
+ function apiErrorBody(error) {
96
+ if (error instanceof SellableApiError)
97
+ return error.body;
98
+ const record = recordValue(error);
99
+ return stringValue(record?.body) ?? stringValue(record?.message);
100
+ }
101
+ export function sourceImportInProgressPayloadFromError(error) {
102
+ if (apiErrorStatus(error) !== 409)
103
+ return null;
104
+ const body = apiErrorBody(error);
105
+ if (!body)
106
+ return null;
107
+ try {
108
+ const parsed = JSON.parse(body);
109
+ const message = stringValue(parsed.error);
110
+ if (message !== "Import already in progress")
111
+ return null;
112
+ return {
113
+ error: message,
114
+ jobId: stringValue(parsed.jobId),
115
+ };
116
+ }
117
+ catch {
118
+ if (!body.includes("Import already in progress"))
119
+ return null;
120
+ return {
121
+ error: "Import already in progress",
122
+ jobId: null,
123
+ };
124
+ }
125
+ }
88
126
  export function paidRefreshActionFrom(value) {
89
127
  const action = recordValue(value);
90
128
  if (!action || action.type !== "refresh_paid_inmail_credits")
@@ -707,6 +745,18 @@ export async function executeOneYoloPrimitive(action, workspaceId) {
707
745
  result = await confirmLeadList(copyInput);
708
746
  }
709
747
  catch (error) {
748
+ const sourceImportInProgress = sourceImportInProgressPayloadFromError(error);
749
+ if (sourceImportInProgress) {
750
+ return {
751
+ status: "read_only_reread",
752
+ result: {
753
+ waited: true,
754
+ reason: "source_import_in_progress",
755
+ jobId: sourceImportInProgress.jobId ?? null,
756
+ error: sourceImportInProgress.error,
757
+ },
758
+ };
759
+ }
710
760
  const rowLimitPayload = userAddedRowsLimitPayloadFromError(error);
711
761
  if (!rowLimitPayload)
712
762
  throw error;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.517",
3
+ "version": "0.1.519",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",