@dench.com/cli 0.4.8 → 2.0.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/crm.ts CHANGED
@@ -48,11 +48,21 @@ import {
48
48
  type FieldCandidate,
49
49
  } from "./lib/crm-enrichment";
50
50
  import {
51
+ aviatoEnrichCompany,
52
+ aviatoEnrichPerson,
51
53
  enrichCompany,
52
54
  EnrichmentGatewayError,
53
55
  enrichPersonByIdentifier,
54
56
  } from "./lib/enrichment-gateway";
55
57
 
58
+ // Contact-info fields that Aviato does not return.
59
+ const CONTACT_REQUIRED_FIELDS = ["phone", "email", "personal_email"] as const;
60
+ type ContactRequiredField = (typeof CONTACT_REQUIRED_FIELDS)[number];
61
+
62
+ function isContactField(field: string): field is ContactRequiredField {
63
+ return (CONTACT_REQUIRED_FIELDS as readonly string[]).includes(field);
64
+ }
65
+
56
66
  type JsonRecord = Record<string, unknown>;
57
67
 
58
68
  const CRM_BATCH_CHUNK_SIZE = 200;
@@ -688,8 +698,32 @@ async function runEntriesCommand(ctx: CrmCliContext): Promise<void> {
688
698
  case "list": {
689
699
  const objectName = shift(ctx.args, "object name");
690
700
  const limit = parseInt(getFlag(ctx.args, "--limit") ?? "100", 10);
701
+ const withMeta = hasFlag(ctx.args, "--with-meta");
691
702
  assertNoUnknownFlags(ctx.args, "crm entries list");
692
- out(ctx, await callQuery(ctx, api.entries.list, { objectName, limit }));
703
+ const entries = await callQuery(ctx, api.entries.list, {
704
+ objectName,
705
+ limit,
706
+ });
707
+ if (!withMeta) {
708
+ out(ctx, entries);
709
+ return;
710
+ }
711
+ const object = (await callQuery(ctx, api.objects.get, {
712
+ name: objectName,
713
+ })) as { entryCount?: number } | null;
714
+ const returnedCount = Array.isArray(entries) ? entries.length : 0;
715
+ const totalCount =
716
+ typeof object?.entryCount === "number"
717
+ ? object.entryCount
718
+ : returnedCount;
719
+ out(ctx, {
720
+ objectName,
721
+ totalCount,
722
+ returnedCount,
723
+ limit,
724
+ hasMore: totalCount > returnedCount,
725
+ entries,
726
+ });
693
727
  return;
694
728
  }
695
729
  case "get": {
@@ -1657,6 +1691,8 @@ async function resolveEnrichmentTarget(
1657
1691
  async function callEnrichmentGatewayForEntry(args: {
1658
1692
  target: EnrichmentTarget;
1659
1693
  entry: CrmEntryForEnrichment;
1694
+ /** Explicit provider override. Defaults: people=fullenrich, company=aviato. */
1695
+ provider?: string;
1660
1696
  }): Promise<Record<string, unknown>> {
1661
1697
  const input = args.entry.fields[args.target.inputField.name];
1662
1698
  if (!hasCellValue(input)) {
@@ -1665,13 +1701,42 @@ async function callEnrichmentGatewayForEntry(args: {
1665
1701
  );
1666
1702
  }
1667
1703
  const inputValue = String(input);
1668
- if (args.target.category === "people") {
1669
- return await enrichPersonByIdentifier(inputValue, args.target.requiredFields);
1704
+ const isCompany = args.target.category === "company";
1705
+ const resolvedProvider = args.provider ?? (isCompany ? "aviato" : "fullenrich");
1706
+
1707
+ if (resolvedProvider === "aviato") {
1708
+ // Guard: Aviato does not return phone or email.
1709
+ const contactFields = args.target.requiredFields.filter(isContactField);
1710
+ if (contactFields.length > 0) {
1711
+ throw new CrmCliError(
1712
+ `Aviato does not return phone or email; use --provider fullenrich for contact fields (${contactFields.join(", ")}).`,
1713
+ );
1714
+ }
1715
+
1716
+ if (isCompany) {
1717
+ // inputValue is typically a domain; try to detect linkedin URLs
1718
+ const isLinkedin = /linkedin\.com/i.test(inputValue);
1719
+ return aviatoEnrichCompany(
1720
+ isLinkedin ? { linkedinUrl: inputValue } : { website: inputValue },
1721
+ );
1722
+ } else {
1723
+ // For people, inputValue may be a LinkedIn URL, email, or LinkedIn ID
1724
+ const isLinkedin = /linkedin\.com/i.test(inputValue);
1725
+ const isEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(inputValue);
1726
+ if (isLinkedin) return aviatoEnrichPerson({ linkedinUrl: inputValue });
1727
+ if (isEmail) return aviatoEnrichPerson({ email: inputValue });
1728
+ return aviatoEnrichPerson({ linkedinID: inputValue });
1729
+ }
1670
1730
  }
1671
- return await enrichCompany({
1672
- domain: inputValue,
1673
- requiredFields: args.target.requiredFields,
1674
- });
1731
+
1732
+ // fullenrich path (default for people, explicit override for companies)
1733
+ if (isCompany) {
1734
+ return enrichCompany({
1735
+ domain: inputValue,
1736
+ requiredFields: args.target.requiredFields,
1737
+ });
1738
+ }
1739
+ return enrichPersonByIdentifier(inputValue, args.target.requiredFields);
1675
1740
  }
1676
1741
 
1677
1742
  async function enrichOneEntry(
@@ -1685,6 +1750,7 @@ async function enrichOneEntry(
1685
1750
  const payload = await callEnrichmentGatewayForEntry({
1686
1751
  target: args.target,
1687
1752
  entry: args.entry,
1753
+ provider: args.provider,
1688
1754
  });
1689
1755
  const value = extractEnrichmentValue(payload, args.target.column);
1690
1756
  if (value === null) {
@@ -2049,7 +2115,7 @@ Fields (columns):
2049
2115
  dench crm fields reorder <object> <field1> <field2> <field3> ...
2050
2116
 
2051
2117
  Entries (rows):
2052
- dench crm entries list <object> [--limit N] [--json]
2118
+ dench crm entries list <object> [--limit N] [--with-meta] [--json]
2053
2119
  dench crm entries get <object> <entryId>
2054
2120
  dench crm entries create <object> --data '{"Field":"Value",...}' (alias: --fields)
2055
2121
  dench crm entries create-many <object> --data '[{"Field":"Value",...}]' [--file rows.json] [--idempotency-key <key>]