@elevasis/core 0.20.0 → 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/dist/index.d.ts +108 -0
- package/dist/index.js +177 -27
- package/dist/knowledge/index.d.ts +54 -0
- package/dist/organization-model/index.d.ts +108 -0
- package/dist/organization-model/index.js +177 -27
- package/dist/test-utils/index.d.ts +54 -0
- package/dist/test-utils/index.js +177 -27
- package/package.json +3 -3
- package/src/_gen/__tests__/__snapshots__/contracts.md.snap +6 -1
- package/src/business/acquisition/api-schemas.test.ts +25 -0
- package/src/business/acquisition/api-schemas.ts +125 -2
- package/src/business/acquisition/build-templates.test.ts +28 -0
- package/src/business/acquisition/build-templates.ts +20 -8
- package/src/business/acquisition/types.ts +6 -1
- package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.test.ts +55 -0
- package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.ts +107 -41
- package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.test.ts +48 -0
- package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.ts +99 -0
- package/src/execution/engine/tools/integration/server/adapters/apollo/index.ts +1 -0
- package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.test.ts +18 -0
- package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.ts +194 -0
- package/src/execution/engine/tools/integration/server/adapters/clickup/index.ts +7 -0
- package/src/integrations/credentials/api-schemas.ts +21 -2
- package/src/integrations/credentials/schemas.ts +200 -164
- package/src/organization-model/__tests__/prospecting-ssot.test.ts +7 -4
- package/src/organization-model/domains/prospecting.ts +182 -25
- package/src/organization-model/domains/sales.ts +24 -3
- package/src/platform/constants/versions.ts +1 -1
- package/src/reference/_generated/contracts.md +6 -1
- package/src/server.ts +2 -0
package/dist/test-utils/index.js
CHANGED
|
@@ -19654,6 +19654,13 @@ var LEAD_GEN_STAGE_CATALOG = {
|
|
|
19654
19654
|
order: 2,
|
|
19655
19655
|
entity: "company"
|
|
19656
19656
|
},
|
|
19657
|
+
crawled: {
|
|
19658
|
+
key: "crawled",
|
|
19659
|
+
label: "Websites crawled",
|
|
19660
|
+
description: "Company websites have been crawled (e.g. via Apify) and raw page content stored for downstream LLM analysis.",
|
|
19661
|
+
order: 2.5,
|
|
19662
|
+
entity: "company"
|
|
19663
|
+
},
|
|
19657
19664
|
extracted: {
|
|
19658
19665
|
key: "extracted",
|
|
19659
19666
|
label: "Websites analyzed",
|
|
@@ -19673,7 +19680,9 @@ var LEAD_GEN_STAGE_CATALOG = {
|
|
|
19673
19680
|
label: "Decision-makers found",
|
|
19674
19681
|
description: "Decision-maker contacts discovered and attached to a qualified company.",
|
|
19675
19682
|
order: 6,
|
|
19676
|
-
entity: "company"
|
|
19683
|
+
entity: "company",
|
|
19684
|
+
recordEntity: "contact",
|
|
19685
|
+
recordStageKey: "discovered"
|
|
19677
19686
|
},
|
|
19678
19687
|
// Prospecting — contact discovery
|
|
19679
19688
|
discovered: {
|
|
@@ -19711,7 +19720,8 @@ var LEAD_GEN_STAGE_CATALOG = {
|
|
|
19711
19720
|
label: "Reviewed and exported",
|
|
19712
19721
|
description: "Approved records have been reviewed and exported for handoff.",
|
|
19713
19722
|
order: 10,
|
|
19714
|
-
entity: "
|
|
19723
|
+
entity: "company",
|
|
19724
|
+
additionalEntities: ["contact"]
|
|
19715
19725
|
},
|
|
19716
19726
|
interested: {
|
|
19717
19727
|
key: "interested",
|
|
@@ -19781,18 +19791,47 @@ var FeatureSchema = z.object({
|
|
|
19781
19791
|
});
|
|
19782
19792
|
var ProspectingLifecycleStageSchema = DisplayMetadataSchema.extend({
|
|
19783
19793
|
id: ModelIdSchema,
|
|
19784
|
-
order: z.number().
|
|
19794
|
+
order: z.number().min(0)
|
|
19795
|
+
});
|
|
19796
|
+
var RecordColumnConfigSchema = z.object({
|
|
19797
|
+
key: ModelIdSchema,
|
|
19798
|
+
label: z.string().trim().min(1).max(120),
|
|
19799
|
+
path: z.string().trim().min(1).max(500),
|
|
19800
|
+
width: z.union([z.number().positive(), z.string().trim().min(1).max(100)]).optional(),
|
|
19801
|
+
renderType: z.enum(["text", "badge", "datetime", "count", "json"]).optional(),
|
|
19802
|
+
badgeColor: z.string().trim().min(1).max(40).optional()
|
|
19803
|
+
});
|
|
19804
|
+
var RecordColumnsConfigSchema = z.object({
|
|
19805
|
+
company: z.array(RecordColumnConfigSchema).optional(),
|
|
19806
|
+
contact: z.array(RecordColumnConfigSchema).optional()
|
|
19807
|
+
}).refine((columns) => Boolean(columns.company?.length || columns.contact?.length), {
|
|
19808
|
+
message: "recordColumns must include at least one entity column set"
|
|
19809
|
+
});
|
|
19810
|
+
var CredentialRequirementSchema = z.object({
|
|
19811
|
+
key: ModelIdSchema,
|
|
19812
|
+
provider: ModelIdSchema,
|
|
19813
|
+
credentialType: z.enum(["api-key", "api-key-secret", "oauth", "webhook-secret"]),
|
|
19814
|
+
label: z.string().trim().min(1).max(120),
|
|
19815
|
+
required: z.boolean(),
|
|
19816
|
+
selectionMode: z.enum(["single", "multiple"]).optional(),
|
|
19817
|
+
inputPath: z.string().trim().min(1).max(500),
|
|
19818
|
+
verifyOnRun: z.boolean().optional()
|
|
19785
19819
|
});
|
|
19786
19820
|
var ProspectingBuildTemplateStepSchema = DisplayMetadataSchema.extend({
|
|
19787
19821
|
id: ModelIdSchema,
|
|
19788
19822
|
primaryEntity: z.enum(["company", "contact"]),
|
|
19789
19823
|
outputs: z.array(z.enum(["company", "contact", "export"])).min(1),
|
|
19790
19824
|
stageKey: ModelIdSchema,
|
|
19825
|
+
recordEntity: z.enum(["company", "contact"]).optional(),
|
|
19826
|
+
recordsStageKey: ModelIdSchema.optional(),
|
|
19827
|
+
recordSourceStageKey: ModelIdSchema.optional(),
|
|
19791
19828
|
dependsOn: z.array(ModelIdSchema).optional(),
|
|
19792
19829
|
dependencyMode: z.literal("per-record-eligibility"),
|
|
19793
19830
|
capabilityKey: ModelIdSchema,
|
|
19794
19831
|
defaultBatchSize: z.number().int().positive(),
|
|
19795
|
-
maxBatchSize: z.number().int().positive()
|
|
19832
|
+
maxBatchSize: z.number().int().positive(),
|
|
19833
|
+
recordColumns: RecordColumnsConfigSchema.optional(),
|
|
19834
|
+
credentialRequirements: z.array(CredentialRequirementSchema).optional()
|
|
19796
19835
|
}).refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
|
|
19797
19836
|
message: "defaultBatchSize must be less than or equal to maxBatchSize",
|
|
19798
19837
|
path: ["defaultBatchSize"]
|
|
@@ -19801,6 +19840,62 @@ var ProspectingBuildTemplateSchema = DisplayMetadataSchema.extend({
|
|
|
19801
19840
|
id: ModelIdSchema,
|
|
19802
19841
|
steps: z.array(ProspectingBuildTemplateStepSchema).min(1)
|
|
19803
19842
|
});
|
|
19843
|
+
var DTC_RECORD_COLUMNS = {
|
|
19844
|
+
populated: {
|
|
19845
|
+
company: [
|
|
19846
|
+
{ key: "name", label: "Company", path: "company.name" },
|
|
19847
|
+
{ key: "domain", label: "Domain", path: "company.domain" },
|
|
19848
|
+
{ key: "employee-count", label: "Employees", path: "company.numEmployees", renderType: "count" },
|
|
19849
|
+
{ key: "apollo-industry", label: "Apollo industry", path: "company.category" },
|
|
19850
|
+
{ key: "location", label: "Location", path: "company.locationState" }
|
|
19851
|
+
]
|
|
19852
|
+
},
|
|
19853
|
+
crawled: {
|
|
19854
|
+
company: [
|
|
19855
|
+
{ key: "name", label: "Company", path: "company.name" },
|
|
19856
|
+
{ key: "domain", label: "Domain", path: "company.domain" },
|
|
19857
|
+
{ key: "page-count", label: "Pages", path: "company.enrichmentData.websiteCrawl.pageCount", renderType: "count" },
|
|
19858
|
+
{ key: "crawl-status", label: "Crawl status", path: "processingState.crawled.status", renderType: "badge" }
|
|
19859
|
+
]
|
|
19860
|
+
},
|
|
19861
|
+
extracted: {
|
|
19862
|
+
company: [
|
|
19863
|
+
{ key: "name", label: "Company", path: "company.name" },
|
|
19864
|
+
{ key: "domain", label: "Domain", path: "company.domain" },
|
|
19865
|
+
{ key: "description", label: "Description", path: "company.enrichmentData.websiteCrawl.companyDescription" },
|
|
19866
|
+
{ key: "services", label: "Services", path: "company.enrichmentData.websiteCrawl.services", renderType: "json" },
|
|
19867
|
+
{ key: "automation-gaps", label: "Automation gaps", path: "company.enrichmentData.websiteCrawl.automationGaps", renderType: "json" },
|
|
19868
|
+
{ key: "contact-count", label: "Contacts", path: "company.enrichmentData.websiteCrawl.emailCount", renderType: "count" }
|
|
19869
|
+
]
|
|
19870
|
+
},
|
|
19871
|
+
qualified: {
|
|
19872
|
+
company: [
|
|
19873
|
+
{ key: "name", label: "Company", path: "company.name" },
|
|
19874
|
+
{ key: "domain", label: "Domain", path: "company.domain" },
|
|
19875
|
+
{ key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
|
|
19876
|
+
{ key: "signals", label: "Signals", path: "company.qualificationSignals", renderType: "json" },
|
|
19877
|
+
{ key: "disqualified-reason", label: "Disqualified reason", path: "processingState.qualified.data.disqualifiedReason" }
|
|
19878
|
+
]
|
|
19879
|
+
},
|
|
19880
|
+
decisionMakers: {
|
|
19881
|
+
contact: [
|
|
19882
|
+
{ key: "name", label: "Name", path: "contact.name" },
|
|
19883
|
+
{ key: "title", label: "Title", path: "contact.title" },
|
|
19884
|
+
{ key: "email", label: "Email", path: "contact.email" },
|
|
19885
|
+
{ key: "linkedin", label: "LinkedIn", path: "contact.linkedinUrl" },
|
|
19886
|
+
{ key: "priority-score", label: "Priority", path: "contact.enrichmentData.apollo.priorityScore", renderType: "badge" }
|
|
19887
|
+
]
|
|
19888
|
+
},
|
|
19889
|
+
uploaded: {
|
|
19890
|
+
company: [
|
|
19891
|
+
{ key: "name", label: "Company", path: "company.name" },
|
|
19892
|
+
{ key: "domain", label: "Domain", path: "company.domain" },
|
|
19893
|
+
{ key: "contacts", label: "Contacts", path: "company.enrichmentData.approvedLeadListExport.contacts", renderType: "json" },
|
|
19894
|
+
{ key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
|
|
19895
|
+
{ key: "approval", label: "Approval", path: "company.enrichmentData.approvedLeadListExport.approvalStatus", renderType: "badge" }
|
|
19896
|
+
]
|
|
19897
|
+
}
|
|
19898
|
+
};
|
|
19804
19899
|
z.object({
|
|
19805
19900
|
id: ModelIdSchema,
|
|
19806
19901
|
label: z.string(),
|
|
@@ -19904,7 +19999,45 @@ var PROSPECTING_STEPS = {
|
|
|
19904
19999
|
dependencyMode: "per-record-eligibility",
|
|
19905
20000
|
capabilityKey: "lead-gen.company.apollo-import",
|
|
19906
20001
|
defaultBatchSize: 250,
|
|
19907
|
-
maxBatchSize: 1e3
|
|
20002
|
+
maxBatchSize: 1e3,
|
|
20003
|
+
recordColumns: DTC_RECORD_COLUMNS.populated,
|
|
20004
|
+
credentialRequirements: [
|
|
20005
|
+
{
|
|
20006
|
+
key: "apollo",
|
|
20007
|
+
provider: "apollo",
|
|
20008
|
+
credentialType: "api-key-secret",
|
|
20009
|
+
label: "Apollo API key",
|
|
20010
|
+
required: true,
|
|
20011
|
+
selectionMode: "single",
|
|
20012
|
+
inputPath: "credential"
|
|
20013
|
+
}
|
|
20014
|
+
]
|
|
20015
|
+
},
|
|
20016
|
+
apifyCrawl: {
|
|
20017
|
+
id: "apify-crawl",
|
|
20018
|
+
label: "Websites crawled",
|
|
20019
|
+
description: "Crawl company websites via Apify and store raw page markdown in enrichmentData.websiteCrawl.pages for downstream LLM analysis. Overwrites the synthetic seed Apollo Import wrote with real page content.",
|
|
20020
|
+
primaryEntity: "company",
|
|
20021
|
+
outputs: ["company"],
|
|
20022
|
+
stageKey: "crawled",
|
|
20023
|
+
dependsOn: ["import-apollo-search"],
|
|
20024
|
+
dependencyMode: "per-record-eligibility",
|
|
20025
|
+
capabilityKey: "lead-gen.company.apify-crawl",
|
|
20026
|
+
defaultBatchSize: 50,
|
|
20027
|
+
maxBatchSize: 100,
|
|
20028
|
+
recordColumns: DTC_RECORD_COLUMNS.crawled,
|
|
20029
|
+
credentialRequirements: [
|
|
20030
|
+
{
|
|
20031
|
+
key: "apify",
|
|
20032
|
+
provider: "apify",
|
|
20033
|
+
credentialType: "api-key-secret",
|
|
20034
|
+
label: "Apify API token",
|
|
20035
|
+
required: true,
|
|
20036
|
+
selectionMode: "single",
|
|
20037
|
+
inputPath: "credential",
|
|
20038
|
+
verifyOnRun: true
|
|
20039
|
+
}
|
|
20040
|
+
]
|
|
19908
20041
|
},
|
|
19909
20042
|
analyzeWebsites: {
|
|
19910
20043
|
id: "analyze-websites",
|
|
@@ -19913,11 +20046,12 @@ var PROSPECTING_STEPS = {
|
|
|
19913
20046
|
primaryEntity: "company",
|
|
19914
20047
|
outputs: ["company"],
|
|
19915
20048
|
stageKey: "extracted",
|
|
19916
|
-
dependsOn: ["
|
|
20049
|
+
dependsOn: ["apify-crawl"],
|
|
19917
20050
|
dependencyMode: "per-record-eligibility",
|
|
19918
20051
|
capabilityKey: "lead-gen.company.website-extract",
|
|
19919
20052
|
defaultBatchSize: 50,
|
|
19920
|
-
maxBatchSize: 100
|
|
20053
|
+
maxBatchSize: 100,
|
|
20054
|
+
recordColumns: DTC_RECORD_COLUMNS.extracted
|
|
19921
20055
|
},
|
|
19922
20056
|
scoreDtcFit: {
|
|
19923
20057
|
id: "score-dtc-fit",
|
|
@@ -19930,7 +20064,8 @@ var PROSPECTING_STEPS = {
|
|
|
19930
20064
|
dependencyMode: "per-record-eligibility",
|
|
19931
20065
|
capabilityKey: "lead-gen.company.dtc-subscription-qualify",
|
|
19932
20066
|
defaultBatchSize: 100,
|
|
19933
|
-
maxBatchSize: 250
|
|
20067
|
+
maxBatchSize: 250,
|
|
20068
|
+
recordColumns: DTC_RECORD_COLUMNS.qualified
|
|
19934
20069
|
},
|
|
19935
20070
|
enrichDecisionMakers: {
|
|
19936
20071
|
id: "enrich-decision-makers",
|
|
@@ -19939,37 +20074,52 @@ var PROSPECTING_STEPS = {
|
|
|
19939
20074
|
primaryEntity: "company",
|
|
19940
20075
|
outputs: ["contact"],
|
|
19941
20076
|
stageKey: "decision-makers-enriched",
|
|
20077
|
+
recordEntity: "contact",
|
|
19942
20078
|
dependsOn: ["score-dtc-fit"],
|
|
19943
20079
|
dependencyMode: "per-record-eligibility",
|
|
19944
20080
|
capabilityKey: "lead-gen.contact.apollo-decision-maker-enrich",
|
|
19945
20081
|
defaultBatchSize: 100,
|
|
19946
|
-
maxBatchSize: 250
|
|
19947
|
-
|
|
19948
|
-
|
|
19949
|
-
|
|
19950
|
-
|
|
19951
|
-
|
|
19952
|
-
|
|
19953
|
-
|
|
19954
|
-
|
|
19955
|
-
|
|
19956
|
-
|
|
19957
|
-
|
|
19958
|
-
|
|
19959
|
-
maxBatchSize: 500
|
|
20082
|
+
maxBatchSize: 250,
|
|
20083
|
+
recordColumns: DTC_RECORD_COLUMNS.decisionMakers,
|
|
20084
|
+
credentialRequirements: [
|
|
20085
|
+
{
|
|
20086
|
+
key: "apollo",
|
|
20087
|
+
provider: "apollo",
|
|
20088
|
+
credentialType: "api-key-secret",
|
|
20089
|
+
label: "Apollo API key",
|
|
20090
|
+
required: true,
|
|
20091
|
+
selectionMode: "single",
|
|
20092
|
+
inputPath: "credential"
|
|
20093
|
+
}
|
|
20094
|
+
]
|
|
19960
20095
|
},
|
|
19961
20096
|
reviewAndExport: {
|
|
19962
20097
|
id: "review-and-export",
|
|
19963
20098
|
label: "Reviewed and exported",
|
|
19964
|
-
description: "Operator QC approves or rejects
|
|
20099
|
+
description: "Operator QC approves or rejects qualified companies, then approved records are exported as a lead list with unverified emails.",
|
|
19965
20100
|
primaryEntity: "company",
|
|
19966
20101
|
outputs: ["export"],
|
|
19967
20102
|
stageKey: "uploaded",
|
|
19968
|
-
|
|
20103
|
+
recordsStageKey: "uploaded",
|
|
20104
|
+
recordSourceStageKey: "qualified",
|
|
20105
|
+
dependsOn: ["enrich-decision-makers"],
|
|
19969
20106
|
dependencyMode: "per-record-eligibility",
|
|
19970
20107
|
capabilityKey: "lead-gen.export.list",
|
|
19971
20108
|
defaultBatchSize: 100,
|
|
19972
|
-
maxBatchSize: 250
|
|
20109
|
+
maxBatchSize: 250,
|
|
20110
|
+
recordColumns: DTC_RECORD_COLUMNS.uploaded,
|
|
20111
|
+
credentialRequirements: [
|
|
20112
|
+
{
|
|
20113
|
+
key: "clickup",
|
|
20114
|
+
provider: "clickup",
|
|
20115
|
+
credentialType: "api-key-secret",
|
|
20116
|
+
label: "ClickUp API token",
|
|
20117
|
+
required: true,
|
|
20118
|
+
selectionMode: "single",
|
|
20119
|
+
inputPath: "clickupCredential",
|
|
20120
|
+
verifyOnRun: true
|
|
20121
|
+
}
|
|
20122
|
+
]
|
|
19973
20123
|
}
|
|
19974
20124
|
}
|
|
19975
20125
|
};
|
|
@@ -19991,7 +20141,7 @@ function toProspectingLifecycleStage(stage) {
|
|
|
19991
20141
|
};
|
|
19992
20142
|
}
|
|
19993
20143
|
function leadGenStagesForEntity(entity) {
|
|
19994
|
-
return Object.values(LEAD_GEN_STAGE_CATALOG).filter((stage) => stage.entity === entity).sort((a3, b2) => a3.order - b2.order).map(toProspectingLifecycleStage);
|
|
20144
|
+
return Object.values(LEAD_GEN_STAGE_CATALOG).filter((stage) => stage.entity === entity || stage.additionalEntities?.includes(entity)).sort((a3, b2) => a3.order - b2.order).map(toProspectingLifecycleStage);
|
|
19995
20145
|
}
|
|
19996
20146
|
var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
|
|
19997
20147
|
listEntityId: "leadgen.list",
|
|
@@ -20021,10 +20171,10 @@ var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
|
|
|
20021
20171
|
description: "Prospecting pipeline for DTC subscription or subscription-ready brands where Apollo is the source and contact-enrichment layer, Elevasis handles company research and fit scoring, and approved leads export as an approved lead list.",
|
|
20022
20172
|
steps: [
|
|
20023
20173
|
PROSPECTING_STEPS.dtcApolloClickup.importApolloSearch,
|
|
20174
|
+
PROSPECTING_STEPS.dtcApolloClickup.apifyCrawl,
|
|
20024
20175
|
PROSPECTING_STEPS.dtcApolloClickup.analyzeWebsites,
|
|
20025
20176
|
PROSPECTING_STEPS.dtcApolloClickup.scoreDtcFit,
|
|
20026
20177
|
PROSPECTING_STEPS.dtcApolloClickup.enrichDecisionMakers,
|
|
20027
|
-
PROSPECTING_STEPS.dtcApolloClickup.verifyEmails,
|
|
20028
20178
|
PROSPECTING_STEPS.dtcApolloClickup.reviewAndExport
|
|
20029
20179
|
]
|
|
20030
20180
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elevasis/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Minimal shared constants across Elevasis monorepo",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"rollup-plugin-dts": "^6.3.0",
|
|
42
42
|
"tsup": "^8.0.0",
|
|
43
43
|
"typescript": "5.9.2",
|
|
44
|
-
"@repo/
|
|
45
|
-
"@repo/
|
|
44
|
+
"@repo/eslint-config": "0.0.0",
|
|
45
|
+
"@repo/typescript-config": "0.0.0"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@anthropic-ai/sdk": "^0.62.0",
|
|
@@ -2549,9 +2549,14 @@ export const AcqSubstrateSchemas = {
|
|
|
2549
2549
|
|
|
2550
2550
|
// List members
|
|
2551
2551
|
ListMembersQuery: ListMembersQuerySchema,
|
|
2552
|
+
ListRecordsQuery: ListRecordsQuerySchema,
|
|
2552
2553
|
MemberIdParams: MemberIdParamsSchema,
|
|
2553
2554
|
AcqListMemberResponse: AcqListMemberResponseSchema,
|
|
2554
2555
|
AcqListMembersResponse: AcqListMembersResponseSchema,
|
|
2556
|
+
AcqListCompanyRecordRow: AcqListCompanyRecordRowSchema,
|
|
2557
|
+
AcqListContactRecordRow: AcqListContactRecordRowSchema,
|
|
2558
|
+
ListRecordRow: ListRecordRowSchema,
|
|
2559
|
+
ListRecordsResponse: ListRecordsResponseSchema,
|
|
2555
2560
|
|
|
2556
2561
|
// List companies
|
|
2557
2562
|
ListCompanyIdParams: ListCompanyIdParamsSchema,
|
|
@@ -2709,7 +2714,7 @@ export const ACQ_LIST_COMPANIES_LEAD_GEN_PIPELINE: StatefulPipelineDefinition =
|
|
|
2709
2714
|
{
|
|
2710
2715
|
stageKey: 'outreach',
|
|
2711
2716
|
label: 'Outreach',
|
|
2712
|
-
states: [PENDING_STATE]
|
|
2717
|
+
states: [PENDING_STATE, { stateKey: 'uploaded', label: 'Uploaded' }]
|
|
2713
2718
|
},
|
|
2714
2719
|
{
|
|
2715
2720
|
stageKey: 'prospecting',
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
ListDealsQuerySchema,
|
|
39
39
|
ListDealTasksDueQuerySchema,
|
|
40
40
|
ListMembersQuerySchema,
|
|
41
|
+
ListRecordsQuerySchema,
|
|
41
42
|
ListStatusSchema,
|
|
42
43
|
PipelineStageSchema,
|
|
43
44
|
ScrapingConfigSchema,
|
|
@@ -1601,6 +1602,30 @@ describe('ListMembersQuerySchema', () => {
|
|
|
1601
1602
|
})
|
|
1602
1603
|
})
|
|
1603
1604
|
|
|
1605
|
+
// ---------------------------------------------------------------------------
|
|
1606
|
+
// ListRecordsQuerySchema
|
|
1607
|
+
// ---------------------------------------------------------------------------
|
|
1608
|
+
|
|
1609
|
+
describe('ListRecordsQuerySchema', () => {
|
|
1610
|
+
it('accepts contact records for DTC decision-maker enrichment', () => {
|
|
1611
|
+
const result = ListRecordsQuerySchema.safeParse({
|
|
1612
|
+
entity: 'contact',
|
|
1613
|
+
stage: 'decision-makers-enriched'
|
|
1614
|
+
})
|
|
1615
|
+
|
|
1616
|
+
expect(result.success).toBe(true)
|
|
1617
|
+
})
|
|
1618
|
+
|
|
1619
|
+
it('keeps company records valid for qualified and uploaded stages', () => {
|
|
1620
|
+
expect(ListRecordsQuerySchema.safeParse({ entity: 'company', stage: 'qualified' }).success).toBe(true)
|
|
1621
|
+
expect(ListRecordsQuerySchema.safeParse({ entity: 'company', stage: 'uploaded' }).success).toBe(true)
|
|
1622
|
+
})
|
|
1623
|
+
|
|
1624
|
+
it('still rejects unrelated stage/entity combinations', () => {
|
|
1625
|
+
expect(ListRecordsQuerySchema.safeParse({ entity: 'contact', stage: 'qualified' }).success).toBe(false)
|
|
1626
|
+
})
|
|
1627
|
+
})
|
|
1628
|
+
|
|
1604
1629
|
// ---------------------------------------------------------------------------
|
|
1605
1630
|
// AcqListResponseSchema (forward-compat)
|
|
1606
1631
|
// ---------------------------------------------------------------------------
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import { UuidSchema, NonEmptyStringSchema } from '../../platform/utils/validation'
|
|
3
3
|
import { CRM_PIPELINE_DEFINITION, LEAD_GEN_STAGE_CATALOG } from '../../organization-model/domains/sales'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
CAPABILITY_REGISTRY,
|
|
6
|
+
CredentialRequirementSchema,
|
|
7
|
+
RecordColumnConfigSchema
|
|
8
|
+
} from '../../organization-model/domains/prospecting'
|
|
5
9
|
import { isProspectingBuildTemplateId } from './build-templates'
|
|
6
10
|
export { CrmPriorityBucketKeySchema, CrmPriorityBucketOverrideSchema, CrmPriorityOverrideSchema } from './crm-priority'
|
|
7
11
|
export type { CrmPriorityBucketOverride, CrmPriorityOverride, ResolvedCrmPriorityRuleConfig } from './crm-priority'
|
|
@@ -496,11 +500,21 @@ export const BuildPlanSnapshotStepSchema = z
|
|
|
496
500
|
primaryEntity: z.enum(['company', 'contact']),
|
|
497
501
|
outputs: z.array(z.enum(['company', 'contact', 'export'])).min(1),
|
|
498
502
|
stageKey: LeadGenStageKeySchema,
|
|
503
|
+
recordEntity: z.enum(['company', 'contact']).optional(),
|
|
504
|
+
recordsStageKey: LeadGenStageKeySchema.optional(),
|
|
505
|
+
recordSourceStageKey: LeadGenStageKeySchema.optional(),
|
|
499
506
|
dependsOn: z.array(z.string().trim().min(1).max(100)).optional(),
|
|
500
507
|
dependencyMode: z.literal('per-record-eligibility'),
|
|
501
508
|
capabilityKey: LeadGenCapabilityKeySchema,
|
|
502
509
|
defaultBatchSize: z.number().int().positive(),
|
|
503
|
-
maxBatchSize: z.number().int().positive()
|
|
510
|
+
maxBatchSize: z.number().int().positive(),
|
|
511
|
+
recordColumns: z
|
|
512
|
+
.object({
|
|
513
|
+
company: z.array(RecordColumnConfigSchema).optional(),
|
|
514
|
+
contact: z.array(RecordColumnConfigSchema).optional()
|
|
515
|
+
})
|
|
516
|
+
.optional(),
|
|
517
|
+
credentialRequirements: z.array(CredentialRequirementSchema).optional()
|
|
504
518
|
})
|
|
505
519
|
.refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
|
|
506
520
|
message: 'defaultBatchSize must be less than or equal to maxBatchSize',
|
|
@@ -1063,6 +1077,33 @@ export const ListMembersQuerySchema = z
|
|
|
1063
1077
|
})
|
|
1064
1078
|
.strict()
|
|
1065
1079
|
|
|
1080
|
+
export const ListRecordEntitySchema = z.enum(['company', 'contact'])
|
|
1081
|
+
|
|
1082
|
+
export const ListRecordsQuerySchema = z
|
|
1083
|
+
.object({
|
|
1084
|
+
entity: ListRecordEntitySchema,
|
|
1085
|
+
stage: LeadGenStageKeySchema.optional(),
|
|
1086
|
+
limit: z.coerce.number().int().min(1).max(500).default(50),
|
|
1087
|
+
offset: z.coerce.number().int().min(0).default(0)
|
|
1088
|
+
})
|
|
1089
|
+
.strict()
|
|
1090
|
+
.superRefine((query, ctx) => {
|
|
1091
|
+
if (!query.stage) return
|
|
1092
|
+
|
|
1093
|
+
const stage = LEAD_GEN_STAGE_CATALOG[query.stage]
|
|
1094
|
+
const validEntity =
|
|
1095
|
+
stage?.entity === query.entity ||
|
|
1096
|
+
stage?.additionalEntities?.includes(query.entity) ||
|
|
1097
|
+
stage?.recordEntity === query.entity
|
|
1098
|
+
if (!validEntity) {
|
|
1099
|
+
ctx.addIssue({
|
|
1100
|
+
code: z.ZodIssueCode.custom,
|
|
1101
|
+
message: `stage "${query.stage}" is not valid for ${query.entity} records`,
|
|
1102
|
+
path: ['stage']
|
|
1103
|
+
})
|
|
1104
|
+
}
|
|
1105
|
+
})
|
|
1106
|
+
|
|
1066
1107
|
export const MemberIdParamsSchema = z.object({
|
|
1067
1108
|
memberId: UuidSchema
|
|
1068
1109
|
})
|
|
@@ -1095,6 +1136,77 @@ export const AcqListMembersResponseSchema = z.object({
|
|
|
1095
1136
|
members: z.array(AcqListMemberResponseSchema)
|
|
1096
1137
|
})
|
|
1097
1138
|
|
|
1139
|
+
export const AcqListRecordCompanySummarySchema = z.object({
|
|
1140
|
+
id: z.string(),
|
|
1141
|
+
name: z.string(),
|
|
1142
|
+
domain: z.string().nullable(),
|
|
1143
|
+
website: z.string().nullable(),
|
|
1144
|
+
linkedinUrl: z.string().nullable(),
|
|
1145
|
+
numEmployees: z.number().nullable(),
|
|
1146
|
+
foundedYear: z.number().nullable(),
|
|
1147
|
+
locationCity: z.string().nullable(),
|
|
1148
|
+
locationState: z.string().nullable(),
|
|
1149
|
+
category: z.string().nullable(),
|
|
1150
|
+
segment: z.string().nullable(),
|
|
1151
|
+
status: AcqCompanyStatusSchema,
|
|
1152
|
+
qualificationScore: z.number().nullable(),
|
|
1153
|
+
qualificationSignals: z.record(z.string(), z.unknown()).nullable(),
|
|
1154
|
+
qualificationRubricKey: z.string().nullable()
|
|
1155
|
+
})
|
|
1156
|
+
|
|
1157
|
+
export const AcqListRecordContactSummarySchema = z.object({
|
|
1158
|
+
id: z.string(),
|
|
1159
|
+
email: z.string(),
|
|
1160
|
+
firstName: z.string().nullable(),
|
|
1161
|
+
lastName: z.string().nullable(),
|
|
1162
|
+
title: z.string().nullable(),
|
|
1163
|
+
headline: z.string().nullable(),
|
|
1164
|
+
linkedinUrl: z.string().nullable(),
|
|
1165
|
+
companyId: z.string().nullable(),
|
|
1166
|
+
status: AcqContactStatusSchema,
|
|
1167
|
+
qualificationScore: z.number().nullable(),
|
|
1168
|
+
qualificationSignals: z.record(z.string(), z.unknown()).nullable(),
|
|
1169
|
+
qualificationRubricKey: z.string().nullable()
|
|
1170
|
+
})
|
|
1171
|
+
|
|
1172
|
+
const ListRecordBaseSchema = z.object({
|
|
1173
|
+
id: z.string(),
|
|
1174
|
+
listId: z.string(),
|
|
1175
|
+
pipelineKey: z.string(),
|
|
1176
|
+
stageKey: z.string(),
|
|
1177
|
+
stateKey: z.string(),
|
|
1178
|
+
activityLog: z.unknown(),
|
|
1179
|
+
addedAt: z.string(),
|
|
1180
|
+
addedBy: z.string().nullable(),
|
|
1181
|
+
sourceExecutionId: z.string().nullable(),
|
|
1182
|
+
processingState: z.record(z.string(), z.unknown()).nullable(),
|
|
1183
|
+
enrichmentData: z.record(z.string(), z.unknown()).nullable()
|
|
1184
|
+
})
|
|
1185
|
+
|
|
1186
|
+
export const AcqListCompanyRecordRowSchema = ListRecordBaseSchema.extend({
|
|
1187
|
+
entity: z.literal('company'),
|
|
1188
|
+
companyId: z.string(),
|
|
1189
|
+
company: AcqListRecordCompanySummarySchema.nullable()
|
|
1190
|
+
})
|
|
1191
|
+
|
|
1192
|
+
export const AcqListContactRecordRowSchema = ListRecordBaseSchema.extend({
|
|
1193
|
+
entity: z.literal('contact'),
|
|
1194
|
+
contactId: z.string(),
|
|
1195
|
+
contact: AcqListRecordContactSummarySchema.nullable()
|
|
1196
|
+
})
|
|
1197
|
+
|
|
1198
|
+
export const ListRecordRowSchema = z.discriminatedUnion('entity', [
|
|
1199
|
+
AcqListCompanyRecordRowSchema,
|
|
1200
|
+
AcqListContactRecordRowSchema
|
|
1201
|
+
])
|
|
1202
|
+
|
|
1203
|
+
export const ListRecordsResponseSchema = z.object({
|
|
1204
|
+
data: z.array(ListRecordRowSchema),
|
|
1205
|
+
total: z.number().int().min(0),
|
|
1206
|
+
limit: z.number().int().min(1),
|
|
1207
|
+
offset: z.number().int().min(0)
|
|
1208
|
+
})
|
|
1209
|
+
|
|
1098
1210
|
// ---------------------------------------------------------------------------
|
|
1099
1211
|
// Track B: List Companies API Schemas
|
|
1100
1212
|
// ---------------------------------------------------------------------------
|
|
@@ -1216,9 +1328,14 @@ export const AcqSubstrateSchemas = {
|
|
|
1216
1328
|
|
|
1217
1329
|
// List members
|
|
1218
1330
|
ListMembersQuery: ListMembersQuerySchema,
|
|
1331
|
+
ListRecordsQuery: ListRecordsQuerySchema,
|
|
1219
1332
|
MemberIdParams: MemberIdParamsSchema,
|
|
1220
1333
|
AcqListMemberResponse: AcqListMemberResponseSchema,
|
|
1221
1334
|
AcqListMembersResponse: AcqListMembersResponseSchema,
|
|
1335
|
+
AcqListCompanyRecordRow: AcqListCompanyRecordRowSchema,
|
|
1336
|
+
AcqListContactRecordRow: AcqListContactRecordRowSchema,
|
|
1337
|
+
ListRecordRow: ListRecordRowSchema,
|
|
1338
|
+
ListRecordsResponse: ListRecordsResponseSchema,
|
|
1222
1339
|
|
|
1223
1340
|
// List companies
|
|
1224
1341
|
ListCompanyIdParams: ListCompanyIdParamsSchema,
|
|
@@ -1242,10 +1359,16 @@ export type CreateArtifactRequest = z.infer<typeof CreateArtifactRequestSchema>
|
|
|
1242
1359
|
export type AcqArtifactResponse = z.infer<typeof AcqArtifactResponseSchema>
|
|
1243
1360
|
export type AcqArtifactListResponse = z.infer<typeof AcqArtifactListResponseSchema>
|
|
1244
1361
|
export type ListMembersQuery = z.infer<typeof ListMembersQuerySchema>
|
|
1362
|
+
export type ListRecordEntity = z.infer<typeof ListRecordEntitySchema>
|
|
1363
|
+
export type ListRecordsQuery = z.infer<typeof ListRecordsQuerySchema>
|
|
1245
1364
|
export type MemberIdParams = z.infer<typeof MemberIdParamsSchema>
|
|
1246
1365
|
export type AcqListMemberContactSummary = z.infer<typeof AcqListMemberContactSummarySchema>
|
|
1247
1366
|
export type AcqListMemberResponse = z.infer<typeof AcqListMemberResponseSchema>
|
|
1248
1367
|
export type AcqListMembersResponse = z.infer<typeof AcqListMembersResponseSchema>
|
|
1368
|
+
export type AcqListCompanyRecordRow = z.infer<typeof AcqListCompanyRecordRowSchema>
|
|
1369
|
+
export type AcqListContactRecordRow = z.infer<typeof AcqListContactRecordRowSchema>
|
|
1370
|
+
export type ListRecordRow = z.infer<typeof ListRecordRowSchema>
|
|
1371
|
+
export type ListRecordsResponse = z.infer<typeof ListRecordsResponseSchema>
|
|
1249
1372
|
export type ListCompanyIdParams = z.infer<typeof ListCompanyIdParamsSchema>
|
|
1250
1373
|
export type AcqListCompanyResponse = z.infer<typeof AcqListCompanyResponseSchema>
|
|
1251
1374
|
|
|
@@ -180,12 +180,40 @@ describe('createBuildPlanSnapshotFromTemplateId — "dtc-subscription-apollo-cli
|
|
|
180
180
|
expect(first?.outputs).toContain('contact')
|
|
181
181
|
})
|
|
182
182
|
|
|
183
|
+
it('preserves Apollo credential requirements for source import and decision-maker enrichment', () => {
|
|
184
|
+
const importApolloSearch = snapshot?.steps.find((step) => step.id === 'import-apollo-search')
|
|
185
|
+
const enrichDecisionMakers = snapshot?.steps.find((step) => step.id === 'enrich-decision-makers')
|
|
186
|
+
|
|
187
|
+
const expectedRequirement = {
|
|
188
|
+
key: 'apollo',
|
|
189
|
+
provider: 'apollo',
|
|
190
|
+
credentialType: 'api-key-secret',
|
|
191
|
+
label: 'Apollo API key',
|
|
192
|
+
required: true,
|
|
193
|
+
selectionMode: 'single',
|
|
194
|
+
inputPath: 'credential'
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
expect(importApolloSearch?.credentialRequirements).toEqual([expectedRequirement])
|
|
198
|
+
expect(enrichDecisionMakers?.credentialRequirements).toEqual([expectedRequirement])
|
|
199
|
+
})
|
|
200
|
+
|
|
183
201
|
it('the final step (review-and-export) outputs export', () => {
|
|
184
202
|
const last = snapshot?.steps[snapshot.steps.length - 1]
|
|
185
203
|
expect(last?.id).toBe('review-and-export')
|
|
186
204
|
expect(last?.outputs).toContain('export')
|
|
187
205
|
})
|
|
188
206
|
|
|
207
|
+
it('preserves contact records metadata for the company-owned decision-maker step', () => {
|
|
208
|
+
const decisionMakers = snapshot?.steps.find((step) => step.id === 'enrich-decision-makers')
|
|
209
|
+
expect(decisionMakers).toMatchObject({
|
|
210
|
+
primaryEntity: 'company',
|
|
211
|
+
recordEntity: 'contact',
|
|
212
|
+
stageKey: 'decision-makers-enriched'
|
|
213
|
+
})
|
|
214
|
+
expect(decisionMakers?.recordColumns?.contact?.length).toBeGreaterThan(0)
|
|
215
|
+
})
|
|
216
|
+
|
|
189
217
|
it('steps with descriptions in the catalog include description in the snapshot', () => {
|
|
190
218
|
const withDesc = snapshot?.steps.filter((step) => step.description !== undefined) ?? []
|
|
191
219
|
expect(withDesc.length).toBeGreaterThan(0)
|
|
@@ -29,16 +29,28 @@ export function createBuildPlanSnapshotFromTemplateId(templateId: string): Build
|
|
|
29
29
|
primaryEntity: step.primaryEntity,
|
|
30
30
|
outputs: [...step.outputs],
|
|
31
31
|
stageKey: step.stageKey,
|
|
32
|
+
recordsStageKey: step.recordsStageKey ?? step.stageKey,
|
|
33
|
+
recordSourceStageKey: step.recordSourceStageKey ?? step.recordsStageKey ?? step.stageKey,
|
|
32
34
|
dependencyMode: step.dependencyMode,
|
|
33
35
|
capabilityKey: step.capabilityKey,
|
|
34
36
|
defaultBatchSize: step.defaultBatchSize,
|
|
35
37
|
maxBatchSize: step.maxBatchSize
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (step.description) snapshotStep.description = step.description
|
|
39
|
-
if (step.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (step.description) snapshotStep.description = step.description
|
|
41
|
+
if (step.recordEntity) snapshotStep.recordEntity = step.recordEntity
|
|
42
|
+
if (step.dependsOn?.length) snapshotStep.dependsOn = [...step.dependsOn]
|
|
43
|
+
if (step.credentialRequirements?.length) {
|
|
44
|
+
snapshotStep.credentialRequirements = step.credentialRequirements.map((requirement) => ({ ...requirement }))
|
|
45
|
+
}
|
|
46
|
+
if (step.recordColumns) {
|
|
47
|
+
snapshotStep.recordColumns = {
|
|
48
|
+
...(step.recordColumns.company ? { company: step.recordColumns.company.map((column) => ({ ...column })) } : {}),
|
|
49
|
+
...(step.recordColumns.contact ? { contact: step.recordColumns.contact.map((column) => ({ ...column })) } : {})
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return snapshotStep
|
|
54
|
+
})
|
|
55
|
+
}
|
|
44
56
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Database } from '../../supabase/database.types'
|
|
2
|
-
import type { Capability } from '../../organization-model/domains/prospecting'
|
|
2
|
+
import type { Capability, CredentialRequirement, RecordColumnConfig } from '../../organization-model/domains/prospecting'
|
|
3
3
|
import type { LEAD_GEN_STAGE_CATALOG } from '../../organization-model/domains/sales'
|
|
4
4
|
import type { PipelineStage, ProcessingStageStatus } from './api-schemas'
|
|
5
5
|
|
|
@@ -167,11 +167,16 @@ export interface BuildPlanSnapshotStep {
|
|
|
167
167
|
primaryEntity: BuildPlanSnapshotPrimaryEntity
|
|
168
168
|
outputs: BuildPlanSnapshotOutput[]
|
|
169
169
|
stageKey: string
|
|
170
|
+
recordEntity?: BuildPlanSnapshotPrimaryEntity
|
|
171
|
+
recordsStageKey?: string
|
|
172
|
+
recordSourceStageKey?: string
|
|
170
173
|
dependsOn?: string[]
|
|
171
174
|
dependencyMode: BuildPlanSnapshotDependencyMode
|
|
172
175
|
capabilityKey: string
|
|
173
176
|
defaultBatchSize: number
|
|
174
177
|
maxBatchSize: number
|
|
178
|
+
recordColumns?: Partial<Record<BuildPlanSnapshotPrimaryEntity, RecordColumnConfig[]>>
|
|
179
|
+
credentialRequirements?: CredentialRequirement[]
|
|
175
180
|
}
|
|
176
181
|
|
|
177
182
|
export interface BuildPlanSnapshot {
|