@sellable/mcp 0.1.274 → 0.1.276
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/README.md +14 -3
- package/dist/server.js +30 -0
- package/dist/tools/campaign-ab-test.d.ts +72 -0
- package/dist/tools/campaign-ab-test.js +60 -0
- package/dist/tools/campaign-message-preparation.d.ts +81 -0
- package/dist/tools/campaign-message-preparation.js +86 -0
- package/dist/tools/csv-linkedin.d.ts +23 -0
- package/dist/tools/csv-linkedin.js +167 -7
- package/dist/tools/leads.d.ts +6 -0
- package/dist/tools/leads.js +8 -0
- package/dist/tools/prompts.d.ts +5 -3
- package/dist/tools/prompts.js +2 -0
- package/dist/tools/registry.d.ts +118 -2
- package/dist/tools/registry.js +4 -0
- package/package.json +1 -1
- package/skills/create-ab-test/SKILL.md +77 -0
- package/skills/create-campaign/SKILL.md +33 -1
- package/skills/create-campaign-v2/core/flow.v2.json +1 -1
- package/skills/research/config.json +9 -0
package/README.md
CHANGED
|
@@ -16,9 +16,10 @@ Each message gets 5+ minutes of Claude attention with deep research - no other t
|
|
|
16
16
|
|
|
17
17
|
### Prompt Source Of Truth
|
|
18
18
|
|
|
19
|
-
There are
|
|
19
|
+
There are five public Sellable entrypoints shared across hosts:
|
|
20
20
|
|
|
21
21
|
- `sellable:create-campaign`
|
|
22
|
+
- `sellable:create-ab-test`
|
|
22
23
|
- `sellable:foundation`
|
|
23
24
|
- `sellable:content`
|
|
24
25
|
- `sellable:create-post`
|
|
@@ -29,6 +30,11 @@ the approval-gated workflow from:
|
|
|
29
30
|
|
|
30
31
|
- `mcp/sellable/skills/create-campaign-v2/SKILL.md`
|
|
31
32
|
|
|
33
|
+
The create-ab-test public wrapper prepares clean A/B split lead lists and
|
|
34
|
+
review-copy campaigns from:
|
|
35
|
+
|
|
36
|
+
- `mcp/sellable/skills/create-ab-test/SKILL.md`
|
|
37
|
+
|
|
32
38
|
The foundation public wrapper loads the core identity/company memory workflow
|
|
33
39
|
from:
|
|
34
40
|
|
|
@@ -148,8 +154,9 @@ The installer does the full local setup:
|
|
|
148
154
|
`mcp__sellable__*` tools into skill sessions
|
|
149
155
|
|
|
150
156
|
After the installer passes, fully quit and reopen Codex Desktop. Start a new
|
|
151
|
-
thread and select `Sellable Create Campaign`, `Sellable
|
|
152
|
-
`Sellable Content`, or `Sellable Create Post`; or invoke
|
|
157
|
+
thread and select `Sellable Create Campaign`, `Sellable Create A/B Test`,
|
|
158
|
+
`Sellable Foundation`, `Sellable Content`, or `Sellable Create Post`; or invoke
|
|
159
|
+
`$sellable:create-campaign`, `$sellable:create-ab-test`,
|
|
153
160
|
`$sellable:foundation`, `$sellable:content`, or `$sellable:create-post`. If the app still says
|
|
154
161
|
`mcp__sellable__*` tools are missing after the installer passes, check that
|
|
155
162
|
`~/.codex/config.toml` contains both `[marketplaces.sellable]` and
|
|
@@ -162,19 +169,23 @@ the Sellable MCP tools for Codex Desktop.
|
|
|
162
169
|
Use these names consistently:
|
|
163
170
|
|
|
164
171
|
- Claude Code command: `/sellable:create-campaign`
|
|
172
|
+
- Claude Code command: `/sellable:create-ab-test`
|
|
165
173
|
- Claude Code command: `/sellable:foundation`
|
|
166
174
|
- Claude Code command: `/sellable:content`
|
|
167
175
|
- Claude Code command: `/sellable:create-post`
|
|
168
176
|
- Codex command: `$sellable:create-campaign`
|
|
177
|
+
- Codex command: `$sellable:create-ab-test`
|
|
169
178
|
- Codex command: `$sellable:foundation`
|
|
170
179
|
- Codex command: `$sellable:content`
|
|
171
180
|
- Codex command: `$sellable:create-post`
|
|
172
181
|
- Codex Desktop plugin: `sellable@sellable`
|
|
173
182
|
- Codex visible skill: `Sellable Create Campaign`
|
|
183
|
+
- Codex visible skill: `Sellable Create A/B Test`
|
|
174
184
|
- Codex visible skill: `Sellable Foundation`
|
|
175
185
|
- Codex visible skill: `Sellable Content`
|
|
176
186
|
- Codex visible skill: `Sellable Create Post`
|
|
177
187
|
- Codex skill frontmatter name: `create-campaign`
|
|
188
|
+
- Codex skill frontmatter name: `create-ab-test`
|
|
178
189
|
- Codex skill frontmatter name: `foundation`
|
|
179
190
|
- Codex skill frontmatter name: `content`
|
|
180
191
|
- Codex skill frontmatter name: `create-post`
|
package/dist/server.js
CHANGED
|
@@ -6,7 +6,9 @@ import { getAuthStatus } from "./tools/auth.js";
|
|
|
6
6
|
import { handleAddColumn, handleCommitBlueprint, } from "./tools/blueprint-commit.js";
|
|
7
7
|
import { bootstrapCreateCampaign } from "./tools/bootstrap.js";
|
|
8
8
|
import { getCampaignTableSchema, queueCampaignCells, reviseMessageTemplateAndRerun, selectCampaignCells, waitForCampaignProcessing, } from "./tools/campaign-processing.js";
|
|
9
|
+
import { cancelPrepareCampaignMessages, getPrepareCampaignMessagesStatus, startPrepareCampaignMessages, } from "./tools/campaign-message-preparation.js";
|
|
9
10
|
import { createCampaign, duplicateCampaign, getCampaign, getCampaignMessagesPreview, getCampaigns, pauseCampaign, startCampaign, updateCampaign, updateCampaignBrief, } from "./tools/campaigns.js";
|
|
11
|
+
import { prepareCampaignAbTest } from "./tools/campaign-ab-test.js";
|
|
10
12
|
import { queueCells, updateCell } from "./tools/cells.js";
|
|
11
13
|
import { handleStartCliLogin, handleWaitForCliLogin, } from "./tools/cli-login.js";
|
|
12
14
|
import { calculateLinkedInHookPreviewTool, capturePostIdeaTool, getPostDraftTool, getPostIdeaTool, getPublishedPostTool, listPostDraftIterationsTool, listPostDraftsTool, listPostIdeasTool, listPublishedPostsTool, markPostPublishedTool, renderLinkedInPostPreviewTool, saveHookResearchTool, savePostDraftTool, updatePostDraftTool, updatePublishedPostMetricsTool, } from "./tools/content-posts.js";
|
|
@@ -163,6 +165,25 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
163
165
|
case "get_campaign_messages_preview":
|
|
164
166
|
result = await getCampaignMessagesPreview(args);
|
|
165
167
|
break;
|
|
168
|
+
case "start_prepare_campaign_messages":
|
|
169
|
+
result = await startPrepareCampaignMessages(args);
|
|
170
|
+
if (args?.campaignId) {
|
|
171
|
+
markCampaignContextDirty(args.campaignId, "start_prepare_campaign_messages");
|
|
172
|
+
}
|
|
173
|
+
break;
|
|
174
|
+
case "get_prepare_campaign_messages_status":
|
|
175
|
+
result = await getPrepareCampaignMessagesStatus(args);
|
|
176
|
+
if (args?.campaignId &&
|
|
177
|
+
["succeeded", "cancelled", "failed"].includes(String(result?.status))) {
|
|
178
|
+
markCampaignContextDirty(args.campaignId, "get_prepare_campaign_messages_status");
|
|
179
|
+
}
|
|
180
|
+
break;
|
|
181
|
+
case "cancel_prepare_campaign_messages":
|
|
182
|
+
result = await cancelPrepareCampaignMessages(args);
|
|
183
|
+
if (args?.campaignId) {
|
|
184
|
+
markCampaignContextDirty(args.campaignId, "cancel_prepare_campaign_messages");
|
|
185
|
+
}
|
|
186
|
+
break;
|
|
166
187
|
case "get_campaign_table_schema":
|
|
167
188
|
result = await getCampaignTableSchema(args);
|
|
168
189
|
break;
|
|
@@ -215,6 +236,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
215
236
|
markCampaignContextDirty(result.campaignOfferId, "duplicate_campaign");
|
|
216
237
|
}
|
|
217
238
|
break;
|
|
239
|
+
case "prepare_campaign_ab_test":
|
|
240
|
+
result = await prepareCampaignAbTest(args);
|
|
241
|
+
if (result?.variants?.A?.campaignId) {
|
|
242
|
+
markCampaignContextDirty(result.variants.A.campaignId, "prepare_campaign_ab_test");
|
|
243
|
+
}
|
|
244
|
+
if (result?.variants?.B?.campaignId) {
|
|
245
|
+
markCampaignContextDirty(result.variants.B.campaignId, "prepare_campaign_ab_test");
|
|
246
|
+
}
|
|
247
|
+
break;
|
|
218
248
|
case "update_campaign_brief":
|
|
219
249
|
result = await updateCampaignBrief(args?.campaignId, args?.campaignBrief);
|
|
220
250
|
if (args?.campaignId) {
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export interface PrepareCampaignAbTestInput {
|
|
2
|
+
sourceCampaignId: string;
|
|
3
|
+
variantName: string;
|
|
4
|
+
variantBriefDelta: string;
|
|
5
|
+
variantALabel?: string;
|
|
6
|
+
variantABriefDelta?: string;
|
|
7
|
+
splitStrategy?: "alternating_stable_sort";
|
|
8
|
+
targetCounts?: {
|
|
9
|
+
a?: number;
|
|
10
|
+
b?: number;
|
|
11
|
+
};
|
|
12
|
+
dryRun?: boolean;
|
|
13
|
+
idempotencyKey?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare const campaignAbTestToolDefinitions: {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: string;
|
|
20
|
+
properties: {
|
|
21
|
+
sourceCampaignId: {
|
|
22
|
+
type: string;
|
|
23
|
+
description: string;
|
|
24
|
+
};
|
|
25
|
+
variantName: {
|
|
26
|
+
type: string;
|
|
27
|
+
description: string;
|
|
28
|
+
};
|
|
29
|
+
variantBriefDelta: {
|
|
30
|
+
type: string;
|
|
31
|
+
description: string;
|
|
32
|
+
};
|
|
33
|
+
variantALabel: {
|
|
34
|
+
type: string;
|
|
35
|
+
description: string;
|
|
36
|
+
};
|
|
37
|
+
variantABriefDelta: {
|
|
38
|
+
type: string;
|
|
39
|
+
description: string;
|
|
40
|
+
};
|
|
41
|
+
splitStrategy: {
|
|
42
|
+
type: string;
|
|
43
|
+
enum: string[];
|
|
44
|
+
description: string;
|
|
45
|
+
};
|
|
46
|
+
targetCounts: {
|
|
47
|
+
type: string;
|
|
48
|
+
properties: {
|
|
49
|
+
a: {
|
|
50
|
+
type: string;
|
|
51
|
+
};
|
|
52
|
+
b: {
|
|
53
|
+
type: string;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
additionalProperties: boolean;
|
|
57
|
+
description: string;
|
|
58
|
+
};
|
|
59
|
+
dryRun: {
|
|
60
|
+
type: string;
|
|
61
|
+
description: string;
|
|
62
|
+
};
|
|
63
|
+
idempotencyKey: {
|
|
64
|
+
type: string;
|
|
65
|
+
description: string;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
required: string[];
|
|
69
|
+
additionalProperties: boolean;
|
|
70
|
+
};
|
|
71
|
+
}[];
|
|
72
|
+
export declare function prepareCampaignAbTest(input: PrepareCampaignAbTestInput): Promise<unknown>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { getApi } from "../api.js";
|
|
2
|
+
export const campaignAbTestToolDefinitions = [
|
|
3
|
+
{
|
|
4
|
+
name: "prepare_campaign_ab_test",
|
|
5
|
+
description: "Prepare a campaign A/B test from an existing campaign using its clean source lead list. Creates deterministic A/B split lead lists and review-copy campaigns, updates the variant brief, and never launches either campaign.",
|
|
6
|
+
inputSchema: {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: {
|
|
9
|
+
sourceCampaignId: {
|
|
10
|
+
type: "string",
|
|
11
|
+
description: "Existing source campaign ID.",
|
|
12
|
+
},
|
|
13
|
+
variantName: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "Short label for variant B, e.g. New CTA.",
|
|
16
|
+
},
|
|
17
|
+
variantBriefDelta: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "The specific campaign brief/copy change for variant B.",
|
|
20
|
+
},
|
|
21
|
+
variantALabel: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "Optional label for the control variant.",
|
|
24
|
+
},
|
|
25
|
+
variantABriefDelta: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "Optional explicit brief change for variant A. Omit for unchanged control.",
|
|
28
|
+
},
|
|
29
|
+
splitStrategy: {
|
|
30
|
+
type: "string",
|
|
31
|
+
enum: ["alternating_stable_sort"],
|
|
32
|
+
description: "Deterministic split strategy. Defaults to alternating_stable_sort.",
|
|
33
|
+
},
|
|
34
|
+
targetCounts: {
|
|
35
|
+
type: "object",
|
|
36
|
+
properties: {
|
|
37
|
+
a: { type: "number" },
|
|
38
|
+
b: { type: "number" },
|
|
39
|
+
},
|
|
40
|
+
additionalProperties: false,
|
|
41
|
+
description: "Optional exact split counts. Omit for an even alternating split.",
|
|
42
|
+
},
|
|
43
|
+
dryRun: {
|
|
44
|
+
type: "boolean",
|
|
45
|
+
description: "When true, returns split plan and review names without creating campaigns/lists.",
|
|
46
|
+
},
|
|
47
|
+
idempotencyKey: {
|
|
48
|
+
type: "string",
|
|
49
|
+
description: "Optional stable key for retrying the same A/B preparation safely.",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
required: ["sourceCampaignId", "variantName", "variantBriefDelta"],
|
|
53
|
+
additionalProperties: false,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
export async function prepareCampaignAbTest(input) {
|
|
58
|
+
const api = getApi();
|
|
59
|
+
return api.post("/api/v3/mcp/campaign-ab-test", input);
|
|
60
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
type ApprovalMode = "mark_ready" | "approve";
|
|
2
|
+
type PrepareMessagesBaseInput = {
|
|
3
|
+
campaignId?: string;
|
|
4
|
+
tableId?: string;
|
|
5
|
+
jobId?: string;
|
|
6
|
+
};
|
|
7
|
+
type StartPrepareMessagesInput = PrepareMessagesBaseInput & {
|
|
8
|
+
campaignId: string;
|
|
9
|
+
targetPreparedMessages?: number;
|
|
10
|
+
maxRowsToCheck?: number;
|
|
11
|
+
batchSize?: number;
|
|
12
|
+
approvalMode?: ApprovalMode;
|
|
13
|
+
autoContinue?: boolean;
|
|
14
|
+
};
|
|
15
|
+
type StatusPrepareMessagesInput = PrepareMessagesBaseInput;
|
|
16
|
+
type CancelPrepareMessagesInput = PrepareMessagesBaseInput;
|
|
17
|
+
export declare const campaignMessagePreparationToolDefinitions: ({
|
|
18
|
+
name: string;
|
|
19
|
+
description: string;
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: string;
|
|
22
|
+
properties: {
|
|
23
|
+
campaignId: {
|
|
24
|
+
type: string;
|
|
25
|
+
description: string;
|
|
26
|
+
};
|
|
27
|
+
tableId: {
|
|
28
|
+
type: string;
|
|
29
|
+
};
|
|
30
|
+
targetPreparedMessages: {
|
|
31
|
+
type: string;
|
|
32
|
+
};
|
|
33
|
+
maxRowsToCheck: {
|
|
34
|
+
type: string;
|
|
35
|
+
};
|
|
36
|
+
batchSize: {
|
|
37
|
+
type: string;
|
|
38
|
+
};
|
|
39
|
+
approvalMode: {
|
|
40
|
+
type: string;
|
|
41
|
+
enum: string[];
|
|
42
|
+
description: string;
|
|
43
|
+
};
|
|
44
|
+
autoContinue: {
|
|
45
|
+
type: string;
|
|
46
|
+
};
|
|
47
|
+
jobId?: undefined;
|
|
48
|
+
};
|
|
49
|
+
required: string[];
|
|
50
|
+
additionalProperties: boolean;
|
|
51
|
+
};
|
|
52
|
+
} | {
|
|
53
|
+
name: string;
|
|
54
|
+
description: string;
|
|
55
|
+
inputSchema: {
|
|
56
|
+
type: string;
|
|
57
|
+
properties: {
|
|
58
|
+
jobId: {
|
|
59
|
+
type: string;
|
|
60
|
+
};
|
|
61
|
+
campaignId: {
|
|
62
|
+
type: string;
|
|
63
|
+
description?: undefined;
|
|
64
|
+
};
|
|
65
|
+
tableId: {
|
|
66
|
+
type: string;
|
|
67
|
+
};
|
|
68
|
+
targetPreparedMessages?: undefined;
|
|
69
|
+
maxRowsToCheck?: undefined;
|
|
70
|
+
batchSize?: undefined;
|
|
71
|
+
approvalMode?: undefined;
|
|
72
|
+
autoContinue?: undefined;
|
|
73
|
+
};
|
|
74
|
+
additionalProperties: boolean;
|
|
75
|
+
required?: undefined;
|
|
76
|
+
};
|
|
77
|
+
})[];
|
|
78
|
+
export declare function startPrepareCampaignMessages(input: StartPrepareMessagesInput): Promise<unknown>;
|
|
79
|
+
export declare function getPrepareCampaignMessagesStatus(input: StatusPrepareMessagesInput): Promise<unknown>;
|
|
80
|
+
export declare function cancelPrepareCampaignMessages(input: CancelPrepareMessagesInput): Promise<unknown>;
|
|
81
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { getApi } from "../api.js";
|
|
2
|
+
async function postPrepareMessages(body) {
|
|
3
|
+
const api = getApi();
|
|
4
|
+
return api.post("/api/v3/mcp/campaign-message-preparation", body);
|
|
5
|
+
}
|
|
6
|
+
export const campaignMessagePreparationToolDefinitions = [
|
|
7
|
+
{
|
|
8
|
+
name: "start_prepare_campaign_messages",
|
|
9
|
+
description: 'Start a bounded Prepare Messages job for a CampaignOffer campaignId. Use this after lead/message approval when the user asks for a target like "prepare 100 messages"; default approvalMode is mark_ready and it never starts the campaign.',
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
campaignId: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "CampaignOffer.id for the campaign whose workflow table should prepare messages.",
|
|
16
|
+
},
|
|
17
|
+
tableId: { type: "string" },
|
|
18
|
+
targetPreparedMessages: { type: "number" },
|
|
19
|
+
maxRowsToCheck: { type: "number" },
|
|
20
|
+
batchSize: { type: "number" },
|
|
21
|
+
approvalMode: {
|
|
22
|
+
type: "string",
|
|
23
|
+
enum: ["mark_ready", "approve"],
|
|
24
|
+
description: 'Defaults to mark_ready. Use approve only when the user explicitly asks to flip Approved cells.',
|
|
25
|
+
},
|
|
26
|
+
autoContinue: { type: "boolean" },
|
|
27
|
+
},
|
|
28
|
+
required: ["campaignId"],
|
|
29
|
+
additionalProperties: false,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "get_prepare_campaign_messages_status",
|
|
34
|
+
description: "Poll compact Prepare Messages progress: checked rows, prepared/approved count, target, remaining row budget, warnings, and stop reason. Does not return raw rows or message bodies.",
|
|
35
|
+
inputSchema: {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
jobId: { type: "string" },
|
|
39
|
+
campaignId: { type: "string" },
|
|
40
|
+
tableId: { type: "string" },
|
|
41
|
+
},
|
|
42
|
+
additionalProperties: false,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "cancel_prepare_campaign_messages",
|
|
47
|
+
description: "Cancel an active Prepare Messages job. Cancellation is cooperative and launch remains a separate explicit start_campaign step.",
|
|
48
|
+
inputSchema: {
|
|
49
|
+
type: "object",
|
|
50
|
+
properties: {
|
|
51
|
+
jobId: { type: "string" },
|
|
52
|
+
campaignId: { type: "string" },
|
|
53
|
+
tableId: { type: "string" },
|
|
54
|
+
},
|
|
55
|
+
additionalProperties: false,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
export function startPrepareCampaignMessages(input) {
|
|
60
|
+
return postPrepareMessages({
|
|
61
|
+
action: "start",
|
|
62
|
+
campaignId: input.campaignId,
|
|
63
|
+
tableId: input.tableId,
|
|
64
|
+
targetPreparedMessages: input.targetPreparedMessages,
|
|
65
|
+
maxRowsToCheck: input.maxRowsToCheck,
|
|
66
|
+
batchSize: input.batchSize,
|
|
67
|
+
approvalMode: input.approvalMode,
|
|
68
|
+
autoContinue: input.autoContinue,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
export function getPrepareCampaignMessagesStatus(input) {
|
|
72
|
+
return postPrepareMessages({
|
|
73
|
+
action: "status",
|
|
74
|
+
jobId: input.jobId,
|
|
75
|
+
campaignId: input.campaignId,
|
|
76
|
+
tableId: input.tableId,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
export function cancelPrepareCampaignMessages(input) {
|
|
80
|
+
return postPrepareMessages({
|
|
81
|
+
action: "cancel",
|
|
82
|
+
jobId: input.jobId,
|
|
83
|
+
campaignId: input.campaignId,
|
|
84
|
+
tableId: input.tableId,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
@@ -9,6 +9,18 @@ export type CsvLinkedinLimits = {
|
|
|
9
9
|
maxRows: number;
|
|
10
10
|
maxCarryColumns: number;
|
|
11
11
|
};
|
|
12
|
+
export type CsvLinkedinIgnoredReservedColumn = {
|
|
13
|
+
originalHeader: string;
|
|
14
|
+
canonicalName: string;
|
|
15
|
+
reason: string;
|
|
16
|
+
};
|
|
17
|
+
export type CsvLinkedinContentFingerprint = {
|
|
18
|
+
fileSha256: string;
|
|
19
|
+
sanitizedHeaderSha256: string;
|
|
20
|
+
selectedColumnsSha256: string;
|
|
21
|
+
ignoredReservedColumnsSha256: string;
|
|
22
|
+
rowCount: number;
|
|
23
|
+
};
|
|
12
24
|
export type CsvLinkedinPreview = {
|
|
13
25
|
resolvedFilePath: string;
|
|
14
26
|
suggestedLeadListName: string;
|
|
@@ -26,6 +38,8 @@ export type CsvLinkedinPreview = {
|
|
|
26
38
|
duplicateLinkedInCount: number;
|
|
27
39
|
emptyLinkedInRowCount: number;
|
|
28
40
|
duplicatePolicy: "first_wins";
|
|
41
|
+
ignoredReservedColumns: CsvLinkedinIgnoredReservedColumn[];
|
|
42
|
+
reservedColumnWarning: string | null;
|
|
29
43
|
limits: CsvLinkedinLimits;
|
|
30
44
|
warnings: string[];
|
|
31
45
|
blockingErrors: string[];
|
|
@@ -38,6 +52,8 @@ export type CsvLinkedinConfirmationPayload = {
|
|
|
38
52
|
fileMtimeMs: number;
|
|
39
53
|
linkedInColumn: string;
|
|
40
54
|
selectedColumns: string[];
|
|
55
|
+
ignoredReservedColumns: CsvLinkedinIgnoredReservedColumn[];
|
|
56
|
+
contentFingerprint: CsvLinkedinContentFingerprint;
|
|
41
57
|
};
|
|
42
58
|
export type PreparedLinkedinLeadRow = {
|
|
43
59
|
row: Record<string, string>;
|
|
@@ -76,6 +92,9 @@ type ParsedCsvLinkedinFile = {
|
|
|
76
92
|
headers: string[];
|
|
77
93
|
rows: Array<Record<string, string>>;
|
|
78
94
|
totalRows: number;
|
|
95
|
+
ignoredReservedColumns: CsvLinkedinIgnoredReservedColumn[];
|
|
96
|
+
reservedColumnWarning: string | null;
|
|
97
|
+
fileSha256: string;
|
|
79
98
|
blockingErrors: string[];
|
|
80
99
|
warnings: string[];
|
|
81
100
|
};
|
|
@@ -86,6 +105,10 @@ export type LinkedInValidationResult = {
|
|
|
86
105
|
valid: false;
|
|
87
106
|
reason: string;
|
|
88
107
|
};
|
|
108
|
+
export declare function getReservedWorkflowColumnMatch(header: string): {
|
|
109
|
+
canonicalName: string;
|
|
110
|
+
reason: string;
|
|
111
|
+
} | null;
|
|
89
112
|
export declare function validateAndNormalizeLinkedInUrl(value: string): LinkedInValidationResult;
|
|
90
113
|
export declare function makeLinkedinConfirmationToken(payload: CsvLinkedinConfirmationPayload): string;
|
|
91
114
|
export declare function parseLinkedinConfirmationToken(token: string): CsvLinkedinConfirmationPayload;
|