@elevasis/core 0.19.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.
Files changed (40) hide show
  1. package/dist/index.d.ts +108 -0
  2. package/dist/index.js +239 -27
  3. package/dist/knowledge/index.d.ts +55 -1
  4. package/dist/organization-model/index.d.ts +108 -0
  5. package/dist/organization-model/index.js +239 -27
  6. package/dist/test-utils/index.d.ts +54 -0
  7. package/dist/test-utils/index.js +238 -27
  8. package/package.json +1 -1
  9. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +17 -5
  10. package/src/business/acquisition/api-schemas.test.ts +125 -14
  11. package/src/business/acquisition/api-schemas.ts +161 -11
  12. package/src/business/acquisition/build-templates.test.ts +28 -0
  13. package/src/business/acquisition/build-templates.ts +20 -8
  14. package/src/business/acquisition/derive-actions.test.ts +1 -1
  15. package/src/business/acquisition/types.ts +7 -2
  16. package/src/business/deals/api-schemas.ts +2 -2
  17. package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.test.ts +55 -0
  18. package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.ts +107 -41
  19. package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.test.ts +48 -0
  20. package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.ts +99 -0
  21. package/src/execution/engine/tools/integration/server/adapters/apollo/index.ts +1 -0
  22. package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.test.ts +18 -0
  23. package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.ts +194 -0
  24. package/src/execution/engine/tools/integration/server/adapters/clickup/index.ts +7 -0
  25. package/src/integrations/credentials/api-schemas.ts +21 -2
  26. package/src/integrations/credentials/schemas.ts +200 -164
  27. package/src/organization-model/__tests__/graph.test.ts +108 -2
  28. package/src/organization-model/__tests__/prospecting-ssot.test.ts +12 -12
  29. package/src/organization-model/__tests__/schema.test.ts +122 -0
  30. package/src/organization-model/__tests__/surface-projection.test.ts +174 -0
  31. package/src/organization-model/domains/prospecting.ts +273 -41
  32. package/src/organization-model/domains/sales.ts +32 -8
  33. package/src/organization-model/graph/build.ts +74 -0
  34. package/src/organization-model/graph/schema.ts +1 -0
  35. package/src/organization-model/graph/types.ts +1 -0
  36. package/src/organization-model/schema.ts +63 -0
  37. package/src/organization-model/surface-projection.ts +218 -0
  38. package/src/platform/constants/versions.ts +1 -1
  39. package/src/reference/_generated/contracts.md +17 -5
  40. package/src/server.ts +2 -0
@@ -585,11 +585,65 @@ declare const OrganizationModelSchema: z.ZodObject<{
585
585
  export: "export";
586
586
  }>>;
587
587
  stageKey: z.ZodString;
588
+ recordEntity: z.ZodOptional<z.ZodEnum<{
589
+ company: "company";
590
+ contact: "contact";
591
+ }>>;
592
+ recordsStageKey: z.ZodOptional<z.ZodString>;
593
+ recordSourceStageKey: z.ZodOptional<z.ZodString>;
588
594
  dependsOn: z.ZodOptional<z.ZodArray<z.ZodString>>;
589
595
  dependencyMode: z.ZodLiteral<"per-record-eligibility">;
590
596
  capabilityKey: z.ZodString;
591
597
  defaultBatchSize: z.ZodNumber;
592
598
  maxBatchSize: z.ZodNumber;
599
+ recordColumns: z.ZodOptional<z.ZodObject<{
600
+ company: z.ZodOptional<z.ZodArray<z.ZodObject<{
601
+ key: z.ZodString;
602
+ label: z.ZodString;
603
+ path: z.ZodString;
604
+ width: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
605
+ renderType: z.ZodOptional<z.ZodEnum<{
606
+ text: "text";
607
+ badge: "badge";
608
+ datetime: "datetime";
609
+ count: "count";
610
+ json: "json";
611
+ }>>;
612
+ badgeColor: z.ZodOptional<z.ZodString>;
613
+ }, z.core.$strip>>>;
614
+ contact: z.ZodOptional<z.ZodArray<z.ZodObject<{
615
+ key: z.ZodString;
616
+ label: z.ZodString;
617
+ path: z.ZodString;
618
+ width: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
619
+ renderType: z.ZodOptional<z.ZodEnum<{
620
+ text: "text";
621
+ badge: "badge";
622
+ datetime: "datetime";
623
+ count: "count";
624
+ json: "json";
625
+ }>>;
626
+ badgeColor: z.ZodOptional<z.ZodString>;
627
+ }, z.core.$strip>>>;
628
+ }, z.core.$strip>>;
629
+ credentialRequirements: z.ZodOptional<z.ZodArray<z.ZodObject<{
630
+ key: z.ZodString;
631
+ provider: z.ZodString;
632
+ credentialType: z.ZodEnum<{
633
+ "api-key": "api-key";
634
+ "api-key-secret": "api-key-secret";
635
+ oauth: "oauth";
636
+ "webhook-secret": "webhook-secret";
637
+ }>;
638
+ label: z.ZodString;
639
+ required: z.ZodBoolean;
640
+ selectionMode: z.ZodOptional<z.ZodEnum<{
641
+ single: "single";
642
+ multiple: "multiple";
643
+ }>>;
644
+ inputPath: z.ZodString;
645
+ verifyOnRun: z.ZodOptional<z.ZodBoolean>;
646
+ }, z.core.$strip>>>;
593
647
  }, z.core.$strip>>;
594
648
  }, z.core.$strip>>;
595
649
  }, z.core.$strip>;
@@ -1996,11 +2050,65 @@ declare const OrganizationModelProspectingSchema: z.ZodObject<{
1996
2050
  export: "export";
1997
2051
  }>>;
1998
2052
  stageKey: z.ZodString;
2053
+ recordEntity: z.ZodOptional<z.ZodEnum<{
2054
+ company: "company";
2055
+ contact: "contact";
2056
+ }>>;
2057
+ recordsStageKey: z.ZodOptional<z.ZodString>;
2058
+ recordSourceStageKey: z.ZodOptional<z.ZodString>;
1999
2059
  dependsOn: z.ZodOptional<z.ZodArray<z.ZodString>>;
2000
2060
  dependencyMode: z.ZodLiteral<"per-record-eligibility">;
2001
2061
  capabilityKey: z.ZodString;
2002
2062
  defaultBatchSize: z.ZodNumber;
2003
2063
  maxBatchSize: z.ZodNumber;
2064
+ recordColumns: z.ZodOptional<z.ZodObject<{
2065
+ company: z.ZodOptional<z.ZodArray<z.ZodObject<{
2066
+ key: z.ZodString;
2067
+ label: z.ZodString;
2068
+ path: z.ZodString;
2069
+ width: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
2070
+ renderType: z.ZodOptional<z.ZodEnum<{
2071
+ text: "text";
2072
+ badge: "badge";
2073
+ datetime: "datetime";
2074
+ count: "count";
2075
+ json: "json";
2076
+ }>>;
2077
+ badgeColor: z.ZodOptional<z.ZodString>;
2078
+ }, z.core.$strip>>>;
2079
+ contact: z.ZodOptional<z.ZodArray<z.ZodObject<{
2080
+ key: z.ZodString;
2081
+ label: z.ZodString;
2082
+ path: z.ZodString;
2083
+ width: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
2084
+ renderType: z.ZodOptional<z.ZodEnum<{
2085
+ text: "text";
2086
+ badge: "badge";
2087
+ datetime: "datetime";
2088
+ count: "count";
2089
+ json: "json";
2090
+ }>>;
2091
+ badgeColor: z.ZodOptional<z.ZodString>;
2092
+ }, z.core.$strip>>>;
2093
+ }, z.core.$strip>>;
2094
+ credentialRequirements: z.ZodOptional<z.ZodArray<z.ZodObject<{
2095
+ key: z.ZodString;
2096
+ provider: z.ZodString;
2097
+ credentialType: z.ZodEnum<{
2098
+ "api-key": "api-key";
2099
+ "api-key-secret": "api-key-secret";
2100
+ oauth: "oauth";
2101
+ "webhook-secret": "webhook-secret";
2102
+ }>;
2103
+ label: z.ZodString;
2104
+ required: z.ZodBoolean;
2105
+ selectionMode: z.ZodOptional<z.ZodEnum<{
2106
+ single: "single";
2107
+ multiple: "multiple";
2108
+ }>>;
2109
+ inputPath: z.ZodString;
2110
+ verifyOnRun: z.ZodOptional<z.ZodBoolean>;
2111
+ }, z.core.$strip>>>;
2004
2112
  }, z.core.$strip>>;
2005
2113
  }, z.core.$strip>>;
2006
2114
  }, z.core.$strip>;
@@ -239,6 +239,13 @@ var LEAD_GEN_STAGE_CATALOG = {
239
239
  order: 2,
240
240
  entity: "company"
241
241
  },
242
+ crawled: {
243
+ key: "crawled",
244
+ label: "Websites crawled",
245
+ description: "Company websites have been crawled (e.g. via Apify) and raw page content stored for downstream LLM analysis.",
246
+ order: 2.5,
247
+ entity: "company"
248
+ },
242
249
  extracted: {
243
250
  key: "extracted",
244
251
  label: "Websites analyzed",
@@ -258,7 +265,9 @@ var LEAD_GEN_STAGE_CATALOG = {
258
265
  label: "Decision-makers found",
259
266
  description: "Decision-maker contacts discovered and attached to a qualified company.",
260
267
  order: 6,
261
- entity: "company"
268
+ entity: "company",
269
+ recordEntity: "contact",
270
+ recordStageKey: "discovered"
262
271
  },
263
272
  // Prospecting — contact discovery
264
273
  discovered: {
@@ -296,7 +305,8 @@ var LEAD_GEN_STAGE_CATALOG = {
296
305
  label: "Reviewed and exported",
297
306
  description: "Approved records have been reviewed and exported for handoff.",
298
307
  order: 10,
299
- entity: "contact"
308
+ entity: "company",
309
+ additionalEntities: ["contact"]
300
310
  },
301
311
  interested: {
302
312
  key: "interested",
@@ -366,18 +376,47 @@ var FeatureSchema = z.object({
366
376
  });
367
377
  var ProspectingLifecycleStageSchema = DisplayMetadataSchema.extend({
368
378
  id: ModelIdSchema,
369
- order: z.number().int().min(0)
379
+ order: z.number().min(0)
380
+ });
381
+ var RecordColumnConfigSchema = z.object({
382
+ key: ModelIdSchema,
383
+ label: z.string().trim().min(1).max(120),
384
+ path: z.string().trim().min(1).max(500),
385
+ width: z.union([z.number().positive(), z.string().trim().min(1).max(100)]).optional(),
386
+ renderType: z.enum(["text", "badge", "datetime", "count", "json"]).optional(),
387
+ badgeColor: z.string().trim().min(1).max(40).optional()
388
+ });
389
+ var RecordColumnsConfigSchema = z.object({
390
+ company: z.array(RecordColumnConfigSchema).optional(),
391
+ contact: z.array(RecordColumnConfigSchema).optional()
392
+ }).refine((columns) => Boolean(columns.company?.length || columns.contact?.length), {
393
+ message: "recordColumns must include at least one entity column set"
394
+ });
395
+ var CredentialRequirementSchema = z.object({
396
+ key: ModelIdSchema,
397
+ provider: ModelIdSchema,
398
+ credentialType: z.enum(["api-key", "api-key-secret", "oauth", "webhook-secret"]),
399
+ label: z.string().trim().min(1).max(120),
400
+ required: z.boolean(),
401
+ selectionMode: z.enum(["single", "multiple"]).optional(),
402
+ inputPath: z.string().trim().min(1).max(500),
403
+ verifyOnRun: z.boolean().optional()
370
404
  });
371
405
  var ProspectingBuildTemplateStepSchema = DisplayMetadataSchema.extend({
372
406
  id: ModelIdSchema,
373
407
  primaryEntity: z.enum(["company", "contact"]),
374
408
  outputs: z.array(z.enum(["company", "contact", "export"])).min(1),
375
409
  stageKey: ModelIdSchema,
410
+ recordEntity: z.enum(["company", "contact"]).optional(),
411
+ recordsStageKey: ModelIdSchema.optional(),
412
+ recordSourceStageKey: ModelIdSchema.optional(),
376
413
  dependsOn: z.array(ModelIdSchema).optional(),
377
414
  dependencyMode: z.literal("per-record-eligibility"),
378
415
  capabilityKey: ModelIdSchema,
379
416
  defaultBatchSize: z.number().int().positive(),
380
- maxBatchSize: z.number().int().positive()
417
+ maxBatchSize: z.number().int().positive(),
418
+ recordColumns: RecordColumnsConfigSchema.optional(),
419
+ credentialRequirements: z.array(CredentialRequirementSchema).optional()
381
420
  }).refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
382
421
  message: "defaultBatchSize must be less than or equal to maxBatchSize",
383
422
  path: ["defaultBatchSize"]
@@ -386,6 +425,68 @@ var ProspectingBuildTemplateSchema = DisplayMetadataSchema.extend({
386
425
  id: ModelIdSchema,
387
426
  steps: z.array(ProspectingBuildTemplateStepSchema).min(1)
388
427
  });
428
+ var DTC_RECORD_COLUMNS = {
429
+ populated: {
430
+ company: [
431
+ { key: "name", label: "Company", path: "company.name" },
432
+ { key: "domain", label: "Domain", path: "company.domain" },
433
+ { key: "employee-count", label: "Employees", path: "company.numEmployees", renderType: "count" },
434
+ { key: "apollo-industry", label: "Apollo industry", path: "company.category" },
435
+ { key: "location", label: "Location", path: "company.locationState" }
436
+ ]
437
+ },
438
+ crawled: {
439
+ company: [
440
+ { key: "name", label: "Company", path: "company.name" },
441
+ { key: "domain", label: "Domain", path: "company.domain" },
442
+ { key: "page-count", label: "Pages", path: "company.enrichmentData.websiteCrawl.pageCount", renderType: "count" },
443
+ { key: "crawl-status", label: "Crawl status", path: "processingState.crawled.status", renderType: "badge" }
444
+ ]
445
+ },
446
+ extracted: {
447
+ company: [
448
+ { key: "name", label: "Company", path: "company.name" },
449
+ { key: "domain", label: "Domain", path: "company.domain" },
450
+ { key: "description", label: "Description", path: "company.enrichmentData.websiteCrawl.companyDescription" },
451
+ { key: "services", label: "Services", path: "company.enrichmentData.websiteCrawl.services", renderType: "json" },
452
+ { key: "automation-gaps", label: "Automation gaps", path: "company.enrichmentData.websiteCrawl.automationGaps", renderType: "json" },
453
+ { key: "contact-count", label: "Contacts", path: "company.enrichmentData.websiteCrawl.emailCount", renderType: "count" }
454
+ ]
455
+ },
456
+ qualified: {
457
+ company: [
458
+ { key: "name", label: "Company", path: "company.name" },
459
+ { key: "domain", label: "Domain", path: "company.domain" },
460
+ { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
461
+ { key: "signals", label: "Signals", path: "company.qualificationSignals", renderType: "json" },
462
+ { key: "disqualified-reason", label: "Disqualified reason", path: "processingState.qualified.data.disqualifiedReason" }
463
+ ]
464
+ },
465
+ decisionMakers: {
466
+ contact: [
467
+ { key: "name", label: "Name", path: "contact.name" },
468
+ { key: "title", label: "Title", path: "contact.title" },
469
+ { key: "email", label: "Email", path: "contact.email" },
470
+ { key: "linkedin", label: "LinkedIn", path: "contact.linkedinUrl" },
471
+ { key: "priority-score", label: "Priority", path: "contact.enrichmentData.apollo.priorityScore", renderType: "badge" }
472
+ ]
473
+ },
474
+ uploaded: {
475
+ company: [
476
+ { key: "name", label: "Company", path: "company.name" },
477
+ { key: "domain", label: "Domain", path: "company.domain" },
478
+ { key: "contacts", label: "Contacts", path: "company.enrichmentData.approvedLeadListExport.contacts", renderType: "json" },
479
+ { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
480
+ { key: "approval", label: "Approval", path: "company.enrichmentData.approvedLeadListExport.approvalStatus", renderType: "badge" }
481
+ ]
482
+ }
483
+ };
484
+ z.object({
485
+ id: ModelIdSchema,
486
+ label: z.string(),
487
+ description: z.string(),
488
+ resourceId: ModelIdSchema
489
+ });
389
490
  var PROSPECTING_STEPS = {
390
491
  localServices: {
391
492
  sourceCompanies: {
@@ -483,7 +584,45 @@ var PROSPECTING_STEPS = {
483
584
  dependencyMode: "per-record-eligibility",
484
585
  capabilityKey: "lead-gen.company.apollo-import",
485
586
  defaultBatchSize: 250,
486
- maxBatchSize: 1e3
587
+ maxBatchSize: 1e3,
588
+ recordColumns: DTC_RECORD_COLUMNS.populated,
589
+ credentialRequirements: [
590
+ {
591
+ key: "apollo",
592
+ provider: "apollo",
593
+ credentialType: "api-key-secret",
594
+ label: "Apollo API key",
595
+ required: true,
596
+ selectionMode: "single",
597
+ inputPath: "credential"
598
+ }
599
+ ]
600
+ },
601
+ apifyCrawl: {
602
+ id: "apify-crawl",
603
+ label: "Websites crawled",
604
+ 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.",
605
+ primaryEntity: "company",
606
+ outputs: ["company"],
607
+ stageKey: "crawled",
608
+ dependsOn: ["import-apollo-search"],
609
+ dependencyMode: "per-record-eligibility",
610
+ capabilityKey: "lead-gen.company.apify-crawl",
611
+ defaultBatchSize: 50,
612
+ maxBatchSize: 100,
613
+ recordColumns: DTC_RECORD_COLUMNS.crawled,
614
+ credentialRequirements: [
615
+ {
616
+ key: "apify",
617
+ provider: "apify",
618
+ credentialType: "api-key-secret",
619
+ label: "Apify API token",
620
+ required: true,
621
+ selectionMode: "single",
622
+ inputPath: "credential",
623
+ verifyOnRun: true
624
+ }
625
+ ]
487
626
  },
488
627
  analyzeWebsites: {
489
628
  id: "analyze-websites",
@@ -492,11 +631,12 @@ var PROSPECTING_STEPS = {
492
631
  primaryEntity: "company",
493
632
  outputs: ["company"],
494
633
  stageKey: "extracted",
495
- dependsOn: ["import-apollo-search"],
634
+ dependsOn: ["apify-crawl"],
496
635
  dependencyMode: "per-record-eligibility",
497
636
  capabilityKey: "lead-gen.company.website-extract",
498
637
  defaultBatchSize: 50,
499
- maxBatchSize: 100
638
+ maxBatchSize: 100,
639
+ recordColumns: DTC_RECORD_COLUMNS.extracted
500
640
  },
501
641
  scoreDtcFit: {
502
642
  id: "score-dtc-fit",
@@ -509,7 +649,8 @@ var PROSPECTING_STEPS = {
509
649
  dependencyMode: "per-record-eligibility",
510
650
  capabilityKey: "lead-gen.company.dtc-subscription-qualify",
511
651
  defaultBatchSize: 100,
512
- maxBatchSize: 250
652
+ maxBatchSize: 250,
653
+ recordColumns: DTC_RECORD_COLUMNS.qualified
513
654
  },
514
655
  enrichDecisionMakers: {
515
656
  id: "enrich-decision-makers",
@@ -518,37 +659,52 @@ var PROSPECTING_STEPS = {
518
659
  primaryEntity: "company",
519
660
  outputs: ["contact"],
520
661
  stageKey: "decision-makers-enriched",
662
+ recordEntity: "contact",
521
663
  dependsOn: ["score-dtc-fit"],
522
664
  dependencyMode: "per-record-eligibility",
523
665
  capabilityKey: "lead-gen.contact.apollo-decision-maker-enrich",
524
666
  defaultBatchSize: 100,
525
- maxBatchSize: 250
526
- },
527
- verifyEmails: {
528
- id: "verify-emails",
529
- label: "Emails verified",
530
- description: "Verify deliverability before the QC and handoff step.",
531
- primaryEntity: "contact",
532
- outputs: ["contact"],
533
- stageKey: "verified",
534
- dependsOn: ["enrich-decision-makers"],
535
- dependencyMode: "per-record-eligibility",
536
- capabilityKey: "lead-gen.contact.verify-email",
537
- defaultBatchSize: 250,
538
- maxBatchSize: 500
667
+ maxBatchSize: 250,
668
+ recordColumns: DTC_RECORD_COLUMNS.decisionMakers,
669
+ credentialRequirements: [
670
+ {
671
+ key: "apollo",
672
+ provider: "apollo",
673
+ credentialType: "api-key-secret",
674
+ label: "Apollo API key",
675
+ required: true,
676
+ selectionMode: "single",
677
+ inputPath: "credential"
678
+ }
679
+ ]
539
680
  },
540
681
  reviewAndExport: {
541
682
  id: "review-and-export",
542
683
  label: "Reviewed and exported",
543
- description: "Operator QC approves or rejects leads, then approved records are exported as a lead list.",
684
+ description: "Operator QC approves or rejects qualified companies, then approved records are exported as a lead list with unverified emails.",
544
685
  primaryEntity: "company",
545
686
  outputs: ["export"],
546
687
  stageKey: "uploaded",
547
- dependsOn: ["verify-emails"],
688
+ recordsStageKey: "uploaded",
689
+ recordSourceStageKey: "qualified",
690
+ dependsOn: ["enrich-decision-makers"],
548
691
  dependencyMode: "per-record-eligibility",
549
692
  capabilityKey: "lead-gen.export.list",
550
693
  defaultBatchSize: 100,
551
- maxBatchSize: 250
694
+ maxBatchSize: 250,
695
+ recordColumns: DTC_RECORD_COLUMNS.uploaded,
696
+ credentialRequirements: [
697
+ {
698
+ key: "clickup",
699
+ provider: "clickup",
700
+ credentialType: "api-key-secret",
701
+ label: "ClickUp API token",
702
+ required: true,
703
+ selectionMode: "single",
704
+ inputPath: "clickupCredential",
705
+ verifyOnRun: true
706
+ }
707
+ ]
552
708
  }
553
709
  }
554
710
  };
@@ -570,7 +726,7 @@ function toProspectingLifecycleStage(stage) {
570
726
  };
571
727
  }
572
728
  function leadGenStagesForEntity(entity) {
573
- return Object.values(LEAD_GEN_STAGE_CATALOG).filter((stage) => stage.entity === entity).sort((a, b) => a.order - b.order).map(toProspectingLifecycleStage);
729
+ return Object.values(LEAD_GEN_STAGE_CATALOG).filter((stage) => stage.entity === entity || stage.additionalEntities?.includes(entity)).sort((a, b) => a.order - b.order).map(toProspectingLifecycleStage);
574
730
  }
575
731
  var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
576
732
  listEntityId: "leadgen.list",
@@ -600,10 +756,10 @@ var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
600
756
  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.",
601
757
  steps: [
602
758
  PROSPECTING_STEPS.dtcApolloClickup.importApolloSearch,
759
+ PROSPECTING_STEPS.dtcApolloClickup.apifyCrawl,
603
760
  PROSPECTING_STEPS.dtcApolloClickup.analyzeWebsites,
604
761
  PROSPECTING_STEPS.dtcApolloClickup.scoreDtcFit,
605
762
  PROSPECTING_STEPS.dtcApolloClickup.enrichDecisionMakers,
606
- PROSPECTING_STEPS.dtcApolloClickup.verifyEmails,
607
763
  PROSPECTING_STEPS.dtcApolloClickup.reviewAndExport
608
764
  ]
609
765
  }
@@ -1124,8 +1280,12 @@ var LEGACY_FEATURE_ALIASES = /* @__PURE__ */ new Map([
1124
1280
  function hasFeature(featuresById, featureId) {
1125
1281
  return featuresById.has(featureId) || featuresById.has(LEGACY_FEATURE_ALIASES.get(featureId) ?? "");
1126
1282
  }
1283
+ function defaultFeaturePathFor(id) {
1284
+ return `/${id.replaceAll(".", "/")}`;
1285
+ }
1127
1286
  var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ctx) => {
1128
1287
  const featuresById = collectIds(model.features, ctx, ["features"], "Feature");
1288
+ const featureIdsByEffectivePath = /* @__PURE__ */ new Map();
1129
1289
  model.features.forEach((feature, featureIndex) => {
1130
1290
  const segments = feature.id.split(".");
1131
1291
  if (segments.length > 1) {
@@ -1141,6 +1301,20 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
1141
1301
  const hasChildren = model.features.some(
1142
1302
  (candidate) => candidate.id.startsWith(`${feature.id}.`) && candidate.id !== feature.id
1143
1303
  );
1304
+ const contributesRoutePath = feature.path !== void 0 || !hasChildren;
1305
+ if (contributesRoutePath) {
1306
+ const effectivePath = feature.path ?? defaultFeaturePathFor(feature.id);
1307
+ const existingFeatureId = featureIdsByEffectivePath.get(effectivePath);
1308
+ if (existingFeatureId !== void 0) {
1309
+ addIssue(
1310
+ ctx,
1311
+ ["features", featureIndex, feature.path === void 0 ? "id" : "path"],
1312
+ `Feature "${feature.id}" effective path "${effectivePath}" duplicates feature "${existingFeatureId}"`
1313
+ );
1314
+ } else {
1315
+ featureIdsByEffectivePath.set(effectivePath, feature.id);
1316
+ }
1317
+ }
1144
1318
  if (hasChildren && feature.enabled) {
1145
1319
  const hasEnabledDescendant = model.features.some(
1146
1320
  (candidate) => candidate.id.startsWith(`${feature.id}.`) && candidate.enabled
@@ -1154,6 +1328,43 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
1154
1328
  }
1155
1329
  }
1156
1330
  });
1331
+ const surfacesById = collectIds(model.navigation.surfaces, ctx, ["navigation", "surfaces"], "Navigation surface");
1332
+ if (model.navigation.defaultSurfaceId !== void 0 && !surfacesById.has(model.navigation.defaultSurfaceId)) {
1333
+ addIssue(
1334
+ ctx,
1335
+ ["navigation", "defaultSurfaceId"],
1336
+ `Navigation defaultSurfaceId references unknown surface "${model.navigation.defaultSurfaceId}"`
1337
+ );
1338
+ }
1339
+ model.navigation.groups.forEach((group, groupIndex) => {
1340
+ group.surfaceIds.forEach((surfaceId, surfaceIndex) => {
1341
+ if (!surfacesById.has(surfaceId)) {
1342
+ addIssue(
1343
+ ctx,
1344
+ ["navigation", "groups", groupIndex, "surfaceIds", surfaceIndex],
1345
+ `Navigation group "${group.id}" references unknown surface "${surfaceId}"`
1346
+ );
1347
+ }
1348
+ });
1349
+ });
1350
+ model.navigation.surfaces.forEach((surface, surfaceIndex) => {
1351
+ if (surface.featureId !== void 0 && !hasFeature(featuresById, surface.featureId)) {
1352
+ addIssue(
1353
+ ctx,
1354
+ ["navigation", "surfaces", surfaceIndex, "featureId"],
1355
+ `Navigation surface "${surface.id}" references unknown feature "${surface.featureId}"`
1356
+ );
1357
+ }
1358
+ surface.featureIds.forEach((featureId, featureIndex) => {
1359
+ if (!hasFeature(featuresById, featureId)) {
1360
+ addIssue(
1361
+ ctx,
1362
+ ["navigation", "surfaces", surfaceIndex, "featureIds", featureIndex],
1363
+ `Navigation surface "${surface.id}" references unknown feature "${featureId}"`
1364
+ );
1365
+ }
1366
+ });
1367
+ });
1157
1368
  const segmentsById = new Map(model.customers.segments.map((seg) => [seg.id, seg]));
1158
1369
  model.offerings.products.forEach((product, productIndex) => {
1159
1370
  product.targetSegmentIds.forEach((segmentId, segmentIndex) => {
@@ -1199,6 +1410,7 @@ var OrganizationGraphNodeKindSchema = z.enum([
1199
1410
  "surface",
1200
1411
  "entity",
1201
1412
  "capability",
1413
+ "stage",
1202
1414
  "resource",
1203
1415
  "knowledge"
1204
1416
  ]);
@@ -3978,11 +3978,65 @@ declare const OrganizationModelSchema: z.ZodObject<{
3978
3978
  export: "export";
3979
3979
  }>>;
3980
3980
  stageKey: z.ZodString;
3981
+ recordEntity: z.ZodOptional<z.ZodEnum<{
3982
+ company: "company";
3983
+ contact: "contact";
3984
+ }>>;
3985
+ recordsStageKey: z.ZodOptional<z.ZodString>;
3986
+ recordSourceStageKey: z.ZodOptional<z.ZodString>;
3981
3987
  dependsOn: z.ZodOptional<z.ZodArray<z.ZodString>>;
3982
3988
  dependencyMode: z.ZodLiteral<"per-record-eligibility">;
3983
3989
  capabilityKey: z.ZodString;
3984
3990
  defaultBatchSize: z.ZodNumber;
3985
3991
  maxBatchSize: z.ZodNumber;
3992
+ recordColumns: z.ZodOptional<z.ZodObject<{
3993
+ company: z.ZodOptional<z.ZodArray<z.ZodObject<{
3994
+ key: z.ZodString;
3995
+ label: z.ZodString;
3996
+ path: z.ZodString;
3997
+ width: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
3998
+ renderType: z.ZodOptional<z.ZodEnum<{
3999
+ text: "text";
4000
+ badge: "badge";
4001
+ datetime: "datetime";
4002
+ count: "count";
4003
+ json: "json";
4004
+ }>>;
4005
+ badgeColor: z.ZodOptional<z.ZodString>;
4006
+ }, z.core.$strip>>>;
4007
+ contact: z.ZodOptional<z.ZodArray<z.ZodObject<{
4008
+ key: z.ZodString;
4009
+ label: z.ZodString;
4010
+ path: z.ZodString;
4011
+ width: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
4012
+ renderType: z.ZodOptional<z.ZodEnum<{
4013
+ text: "text";
4014
+ badge: "badge";
4015
+ datetime: "datetime";
4016
+ count: "count";
4017
+ json: "json";
4018
+ }>>;
4019
+ badgeColor: z.ZodOptional<z.ZodString>;
4020
+ }, z.core.$strip>>>;
4021
+ }, z.core.$strip>>;
4022
+ credentialRequirements: z.ZodOptional<z.ZodArray<z.ZodObject<{
4023
+ key: z.ZodString;
4024
+ provider: z.ZodString;
4025
+ credentialType: z.ZodEnum<{
4026
+ "api-key": "api-key";
4027
+ "api-key-secret": "api-key-secret";
4028
+ oauth: "oauth";
4029
+ "webhook-secret": "webhook-secret";
4030
+ }>;
4031
+ label: z.ZodString;
4032
+ required: z.ZodBoolean;
4033
+ selectionMode: z.ZodOptional<z.ZodEnum<{
4034
+ single: "single";
4035
+ multiple: "multiple";
4036
+ }>>;
4037
+ inputPath: z.ZodString;
4038
+ verifyOnRun: z.ZodOptional<z.ZodBoolean>;
4039
+ }, z.core.$strip>>>;
3986
4040
  }, z.core.$strip>>;
3987
4041
  }, z.core.$strip>>;
3988
4042
  }, z.core.$strip>;