Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@devkiran
Copy link
Collaborator

@devkiran devkiran commented Sep 24, 2025

Summary by CodeRabbit

  • New Features
    • HubSpot integration now auto-creates Dub contact properties after you connect.
  • Refactor
    • Consolidated HubSpot interactions into a single client for more reliable lead and deal syncing.
  • Chores
    • Added required HubSpot scope for managing contact schemas; you may be prompted to reauthorize.
    • Updated default/placeholder for the closed-won deal stage in settings.
  • Documentation
    • Documented CLI command: “pnpm hs account list” to view connected accounts.

@vercel
Copy link
Contributor

vercel bot commented Sep 24, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
dub Ready Ready Preview Sep 24, 2025 6:37pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 24, 2025

Walkthrough

Adds a consolidated HubSpotApi client, removes legacy per-operation helpers, updates tracking and UI modules to use the new API and renamed constant, extends OAuth scopes, schedules a background task in the HubSpot OAuth callback to batch-create contact properties, and updates the HubSpot app manifest and README.

Changes

Cohort / File(s) Summary
New HubSpot API client & removed helpers
apps/web/lib/integrations/hubspot/api.ts, apps/web/lib/integrations/hubspot/get-contact.ts, apps/web/lib/integrations/hubspot/get-deal.ts, apps/web/lib/integrations/hubspot/update-contact.ts
Adds HubSpotApi (constructor, private fetch helper, getContact, getDeal, updateContact, createPropertiesBatch). Removes legacy helper modules get-contact.ts, get-deal.ts, and update-contact.ts.
OAuth callback background task
apps/web/app/(ee)/api/hubspot/callback/route.ts
After installIntegration succeeds, stores the result and uses waitUntil to initialize HubSpotApi with the access token and call createPropertiesBatch (objectType "0-1", HUBSPOT_DUB_CONTACT_PROPERTIES) in background.
Scopes, constants, properties
apps/web/lib/integrations/hubspot/constants.ts, packages/hubspot-app/src/app/app-hsmeta.json, packages/hubspot-app/README.md
Adds crm.schemas.contacts.write to scopes (constants + app manifest). Renames DEFAULT_CLOSED_WON_DEAL_STAGE_IDHUBSPOT_DEFAULT_CLOSED_WON_DEAL_STAGE_ID. Adds HUBSPOT_DUB_CONTACT_PROPERTIES array. README documents new CLI command.
Tracking refactors
apps/web/lib/integrations/hubspot/track-lead.ts, apps/web/lib/integrations/hubspot/track-sale.ts
Replaces direct helper calls with HubSpotApi usage (getContact, getDeal, updateContact), updates imports and uses HUBSPOT_DEFAULT_CLOSED_WON_DEAL_STAGE_ID. Updates _updateHubSpotContact signature to accept hubSpotApi.
UI update
apps/web/lib/integrations/hubspot/ui/settings.tsx
Updates default/placeholder to use HUBSPOT_DEFAULT_CLOSED_WON_DEAL_STAGE_ID instead of the old constant name.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant CB as /api/hubspot/callback
  participant HS as installIntegration
  participant BG as waitUntil (background)
  participant API as HubSpotApi
  note over CB: OAuth callback flow
  U->>CB: Complete HubSpot install
  CB->>HS: installIntegration()
  HS-->>CB: { accessToken, ... }
  alt install succeeded
    CB->>BG: schedule property creation
    BG->>API: new HubSpotApi(token)
    BG->>API: createPropertiesBatch(objectType:"0-1", HUBSPOT_DUB_CONTACT_PROPERTIES)
    API-->>BG: result
  else install failed
    CB-->>U: error response
  end
  CB-->>U: 200/redirect
Loading
sequenceDiagram
  autonumber
  participant E as Event (lead/sale)
  participant S as trackLead / trackSale
  participant API as HubSpotApi
  E->>S: payload + auth token
  S->>API: new HubSpotApi(token)
  par Fetch HubSpot data
    S->>API: getContact(contactId)
    S->>API: getDeal(dealId)
  end
  alt Update needed
    S->>API: updateContact({ contactId, properties })
    API-->>S: update result
  else No update
    S-->>E: no-op
  end
  S-->>E: done
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

  • Hubspot integration #2839 — Refactors HubSpot integration and touches the callback route and helper consolidation; overlaps with this API consolidation and background property creation.
  • Improve HubSpot integration #2874 — Alters HubSpot constants and tracking modules; closely related to replacing helper functions with a central HubSpotApi.

Poem

A rabbit hops in code with a chirp and a grin,
New HubSpot paths where tidy APIs begin.
Background batches planting property seeds,
Contacts and deals fetched to meet our needs.
Hooray for small hops that make big wins! 🥕✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title concisely highlights the primary new feature of scheduling contact property creation during HubSpot integration installation without extraneous detail and clearly identifies the core change in the pull request.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch hubspot-create-properties

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f0b6854 and d6904e2.

📒 Files selected for processing (1)
  • apps/web/lib/integrations/hubspot/constants.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/lib/integrations/hubspot/constants.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@devkiran devkiran requested a review from steven-tey September 24, 2025 07:14
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
apps/web/lib/integrations/hubspot/api.ts (1)

72-72: Align parameter type with contact accessor (accept string IDs as well).

Webhook objectIds can arrive as strings; mirroring getContact’s number | string improves ergonomics.

-  async getDeal(dealId: number) {
+  async getDeal(dealId: number | string) {
apps/web/lib/integrations/hubspot/track-lead.ts (1)

117-124: Avoid unhandled errors in background update; soften DB lookup.

  • _updateHubSpotContact can throw on findUniqueOrThrow; wrap body in try/catch or use findUnique with guard.
  • Also prefer building customerName with filter(Boolean) to avoid "null null".

Example refactor (outside the shown ranges):

export const _updateHubSpotContact = async (args: {
  hubSpotApi: HubSpotApi;
  contact: HubSpotContact;
  trackLeadResult: TrackLeadResponse;
}) => {
  try {
    const { hubSpotApi, contact, trackLeadResult } = args;

    if (contact.properties.dub_link && contact.properties.dub_partner_email) {
      console.log(`[HubSpot] Contact ${contact.id} already updated. Skipping.`);
      return;
    }

    const properties: Record<string, string> = {};

    if (trackLeadResult.link?.partnerId) {
      const partner = await prisma.partner.findUnique({
        where: { id: trackLeadResult.link.partnerId },
        select: { email: true },
      });
      if (partner?.email) properties["dub_partner_email"] = partner.email;
    }

    if (trackLeadResult.link?.shortLink) {
      properties["dub_link"] = trackLeadResult.link.shortLink;
    }

    if (Object.keys(properties).length === 0) return;

    await hubSpotApi.updateContact({ contactId: contact.id, properties });
  } catch (err) {
    console.error("[HubSpot] Failed to update contact with Dub fields:", err);
  }
};

And for building name in the deal branch (outside ranges):

const customerName = [contactInfo.properties.firstname, contactInfo.properties.lastname]
  .filter(Boolean)
  .join(" ") || null;

Also applies to: 159-163

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fcd7d99 and f0b6854.

📒 Files selected for processing (11)
  • apps/web/app/(ee)/api/hubspot/callback/route.ts (3 hunks)
  • apps/web/lib/integrations/hubspot/api.ts (1 hunks)
  • apps/web/lib/integrations/hubspot/constants.ts (2 hunks)
  • apps/web/lib/integrations/hubspot/get-contact.ts (0 hunks)
  • apps/web/lib/integrations/hubspot/get-deal.ts (0 hunks)
  • apps/web/lib/integrations/hubspot/track-lead.ts (8 hunks)
  • apps/web/lib/integrations/hubspot/track-sale.ts (4 hunks)
  • apps/web/lib/integrations/hubspot/ui/settings.tsx (3 hunks)
  • apps/web/lib/integrations/hubspot/update-contact.ts (0 hunks)
  • packages/hubspot-app/README.md (1 hunks)
  • packages/hubspot-app/src/app/app-hsmeta.json (1 hunks)
💤 Files with no reviewable changes (3)
  • apps/web/lib/integrations/hubspot/get-contact.ts
  • apps/web/lib/integrations/hubspot/get-deal.ts
  • apps/web/lib/integrations/hubspot/update-contact.ts
🧰 Additional context used
📓 Path-based instructions (1)
packages/hubspot-app/**/*-hsmeta.json

📄 CodeRabbit inference engine (packages/hubspot-app/CLAUDE.md)

packages/hubspot-app/**/*-hsmeta.json: Component configuration files must be named with the -hsmeta.json suffix
The uid field in -hsmeta.json files must be unique within the project
The type field in -hsmeta.json defines the component type and must be set correctly

Files:

  • packages/hubspot-app/src/app/app-hsmeta.json
🧠 Learnings (8)
📚 Learning: 2025-09-19T18:46:43.787Z
Learnt from: CR
PR: dubinc/dub#0
File: packages/hubspot-app/CLAUDE.md:0-0
Timestamp: 2025-09-19T18:46:43.787Z
Learning: Applies to packages/hubspot-app/app/**/-hsmeta.json : If config.distribution is marketplace in the app component, config.auth.type must be oauth

Applied to files:

  • packages/hubspot-app/src/app/app-hsmeta.json
📚 Learning: 2025-09-19T18:46:43.787Z
Learnt from: CR
PR: dubinc/dub#0
File: packages/hubspot-app/CLAUDE.md:0-0
Timestamp: 2025-09-19T18:46:43.787Z
Learning: Applies to packages/hubspot-app/app/**/-hsmeta.json : Any URLs used via hubspot.fetch in settings must be listed in app component config.permittedUrls.fetch

Applied to files:

  • packages/hubspot-app/src/app/app-hsmeta.json
📚 Learning: 2025-09-17T02:53:28.359Z
Learnt from: devkiran
PR: dubinc/dub#2839
File: apps/web/lib/integrations/hubspot/schema.ts:5-12
Timestamp: 2025-09-17T02:53:28.359Z
Learning: HubSpot's OAuth token response returns `scopes` as an array of strings, not as a space-delimited string. The schema `scopes: z.array(z.string())` in hubSpotAuthTokenSchema is correct for HubSpot's actual API response format.

Applied to files:

  • packages/hubspot-app/src/app/app-hsmeta.json
📚 Learning: 2025-09-19T18:46:43.787Z
Learnt from: CR
PR: dubinc/dub#0
File: packages/hubspot-app/CLAUDE.md:0-0
Timestamp: 2025-09-19T18:46:43.787Z
Learning: Applies to packages/hubspot-app/**/*-hsmeta.json : The type field in -hsmeta.json defines the component type and must be set correctly

Applied to files:

  • packages/hubspot-app/src/app/app-hsmeta.json
📚 Learning: 2025-09-19T18:46:43.787Z
Learnt from: CR
PR: dubinc/dub#0
File: packages/hubspot-app/CLAUDE.md:0-0
Timestamp: 2025-09-19T18:46:43.787Z
Learning: Applies to packages/hubspot-app/app/scim/**/-hsmeta.json : There can only be one scim component and it must be under app/scim

Applied to files:

  • packages/hubspot-app/src/app/app-hsmeta.json
📚 Learning: 2025-09-19T18:46:43.787Z
Learnt from: CR
PR: dubinc/dub#0
File: packages/hubspot-app/CLAUDE.md:0-0
Timestamp: 2025-09-19T18:46:43.787Z
Learning: Applies to packages/hubspot-app/app/**/-hsmeta.json : Any URLs called via hubspot.fetch in UI extensions must be listed in the app component’s config.permittedUrls.fetch

Applied to files:

  • packages/hubspot-app/src/app/app-hsmeta.json
📚 Learning: 2025-09-19T18:46:43.787Z
Learnt from: CR
PR: dubinc/dub#0
File: packages/hubspot-app/CLAUDE.md:0-0
Timestamp: 2025-09-19T18:46:43.787Z
Learning: Applies to packages/hubspot-app/**/*-hsmeta.json : Component configuration files must be named with the -hsmeta.json suffix

Applied to files:

  • packages/hubspot-app/src/app/app-hsmeta.json
📚 Learning: 2025-09-19T18:46:43.787Z
Learnt from: CR
PR: dubinc/dub#0
File: packages/hubspot-app/CLAUDE.md:0-0
Timestamp: 2025-09-19T18:46:43.787Z
Learning: Use hs CLI help and debugging flags (e.g., --help, --debug, hs doctor) and the appropriate hs project/account subcommands

Applied to files:

  • packages/hubspot-app/README.md
🧬 Code graph analysis (5)
apps/web/lib/integrations/hubspot/ui/settings.tsx (1)
apps/web/lib/integrations/hubspot/constants.ts (1)
  • HUBSPOT_DEFAULT_CLOSED_WON_DEAL_STAGE_ID (28-28)
apps/web/lib/integrations/hubspot/track-sale.ts (2)
apps/web/lib/integrations/hubspot/constants.ts (1)
  • HUBSPOT_DEFAULT_CLOSED_WON_DEAL_STAGE_ID (28-28)
apps/web/lib/integrations/hubspot/api.ts (1)
  • HubSpotApi (8-135)
apps/web/app/(ee)/api/hubspot/callback/route.ts (3)
apps/web/lib/integrations/install.ts (1)
  • installIntegration (14-102)
apps/web/lib/integrations/hubspot/api.ts (1)
  • HubSpotApi (8-135)
apps/web/lib/integrations/hubspot/constants.ts (1)
  • HUBSPOT_DUB_CONTACT_PROPERTIES (30-53)
apps/web/lib/integrations/hubspot/api.ts (2)
apps/web/lib/integrations/hubspot/constants.ts (1)
  • HUBSPOT_API_HOST (11-11)
apps/web/lib/integrations/hubspot/schema.ts (2)
  • hubSpotContactSchema (31-41)
  • hubSpotDealSchema (43-60)
apps/web/lib/integrations/hubspot/track-lead.ts (1)
apps/web/lib/integrations/hubspot/api.ts (1)
  • HubSpotApi (8-135)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (8)
apps/web/lib/integrations/hubspot/ui/settings.tsx (2)

9-9: LGTM: renamed constant usage is consistent.

Imports and UI placeholder now align with HUBSPOT_DEFAULT_CLOSED_WON_DEAL_STAGE_ID.


18-19: Nit: keep customer-facing placeholder and default in sync with saved settings.

Already consistent; no action needed.

Also applies to: 66-67

apps/web/lib/integrations/hubspot/track-sale.ts (1)

44-49: Depends on API fix for deals endpoint path.

This will work once HubSpotApi.getDeal uses /objects/deals/{id}. No other changes needed here.

After updating api.ts, sanity-check one event path locally with a sample payload to ensure deal/contact fetches succeed.

apps/web/lib/integrations/hubspot/track-lead.ts (2)

20-27: LGTM: centralizing calls via HubSpotApi.

Constructor usage and swapping to hubSpotApi.getContact are sound.


67-87: LGTM: deal branch mirrors contact branch via HubSpotApi.

The additional fetch to hydrate contact properties is required since associations omit them.

apps/web/lib/integrations/hubspot/constants.ts (2)

13-19: Scopes update aligns with property-creation needs.

Including crm.schemas.contacts.write is required for property schema writes.


28-53: Property definitions look good; no lingering references to the old constant.

git grep shows only HUBSPOT_DEFAULT_CLOSED_WON_DEAL_STAGE_ID in apps/web/lib/integrations/hubspot/constants.ts, apps/web/lib/integrations/hubspot/track-sale.ts, and apps/web/lib/integrations/hubspot/ui/settings.tsx — no matches for DEFAULT_CLOSED_WON_DEAL_STAGE_ID. Confirm manifest scope and runtime creation for these contact properties.

packages/hubspot-app/src/app/app-hsmeta.json (1)

18-20: Approve — scope addition OK; hsmeta UIDs unique

  • Adding crm.schemas.contacts.write aligns with creating contact properties.
  • distribution=marketplace with auth.type=oauth is correct.
  • UIDs across *-hsmeta.json are unique (found: dub, dub-webhooks).

@steven-tey steven-tey merged commit 482805f into main Sep 24, 2025
7 of 8 checks passed
@steven-tey steven-tey deleted the hubspot-create-properties branch September 24, 2025 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants