MCPcopy Index your code
hub / github.com/simstudioai/sim / fetchHubSpotChanges

Function fetchHubSpotChanges

apps/sim/lib/webhooks/polling/hubspot.ts:620–719  ·  view source on GitHub ↗
(args: FetchArgs)

Source from the content-addressed store, hash-verified

618}
619
620async function fetchHubSpotChanges(args: FetchArgs): Promise<HubSpotSearchResult[]> {
621 const {
622 accessToken,
623 objectType,
624 filterProperty,
625 watermarkMs,
626 lastSeenObjectId,
627 properties,
628 userFilters,
629 maxRecords,
630 requestId,
631 logger,
632 } = args
633
634 const url = `https://api.hubapi.com/crm/v3/objects/${encodeURIComponent(resolveSearchPath(objectType))}/search`
635 const accumulated: HubSpotSearchResult[] = []
636 let after: string | undefined
637 let pages = 0
638
639 // Two OR-combined filter groups give a strict monotonic cursor over (timestamp, id):
640 // A: filterProperty > watermark (next timestamps)
641 // B: filterProperty == watermark AND id > lastSeenObjectId (more ids at boundary)
642 // User filters AND into both groups so they apply regardless of which side matches.
643 // Group B is dropped on the first poll after seeding so we don't emit boundary
644 // records the seed point already skipped past.
645 const buildBody = (cursor?: string) => {
646 const groupA: FilterClause[] = [
647 { propertyName: filterProperty, operator: 'GT', value: String(watermarkMs) },
648 ...userFilters,
649 ]
650 const groups = [{ filters: groupA }]
651 if (lastSeenObjectId) {
652 const groupB: FilterClause[] = [
653 { propertyName: filterProperty, operator: 'EQ', value: String(watermarkMs) },
654 { propertyName: 'hs_object_id', operator: 'GT', value: String(lastSeenObjectId) },
655 ...userFilters,
656 ]
657 groups.push({ filters: groupB })
658 }
659 return {
660 filterGroups: groups,
661 sorts: [{ propertyName: filterProperty, direction: 'ASCENDING' }],
662 properties,
663 limit: HUBSPOT_PAGE_LIMIT,
664 ...(cursor ? { after: cursor } : {}),
665 }
666 }
667
668 do {
669 const response = await fetch(url, {
670 method: 'POST',
671 headers: {
672 Authorization: `Bearer ${accessToken}`,
673 'Content-Type': 'application/json',
674 },
675 body: JSON.stringify(buildBody(after)),
676 })
677

Callers 1

pollSearchBasedFunction · 0.85

Calls 8

resolveSearchPathFunction · 0.85
compareObjectIdsFunction · 0.85
textMethod · 0.80
errorMethod · 0.80
buildBodyFunction · 0.70
warnMethod · 0.65
pushMethod · 0.45

Tested by

no test coverage detected