-
Notifications
You must be signed in to change notification settings - Fork 5.5k
HubSpot - adding retry to search endpoint #18215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
⏰ 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). (3)
✨ Finishing Touches🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (27)
components/hubspot/actions/list-marketing-events/list-marketing-events.mjs (2)
20-21: Critical: variable shadowing and mutating the iterated array
resultsis declared as the accumulator (Line 20) and then shadowed by the API response destructure (Line 28). Inside the loop you push into the same array you're iterating, which can lead to incorrect iteration and potential unbounded loops. Also the summary and return reference the wrong array.Apply:
- const results = []; + const items = []; @@ - const { - paging, results, - } = await this.hubspot.listMarketingEvents({ + const { + paging, results: pageResults, + } = await this.hubspot.listMarketingEvents({ @@ - if (!results?.length) { + if (!pageResults?.length) { break; } - for (const item of results) { - results.push(item); + for (const item of pageResults) { + items.push(item); count++; if (count >= this.maxResults) { break; } } @@ - $.export("$summary", `Found ${results.length} event${results.length === 1 + $.export("$summary", `Found ${items.length} event${items.length === 1 ? "" : "s"}`); - return results; + return items;Also applies to: 27-38, 47-50
22-23: Safer paging + limit handling
- Access
paging.next.afterdefensively.- Track the cursor separately from the boolean.
- Reduce over-fetch by limiting to remaining results.
- const params = { - limit: 100, - }; - let hasMore, count = 0; + const params = {}; + let next, count = 0; @@ - hasMore = paging?.next.after; - params.after = paging?.next.after; - } while (hasMore && count < this.maxResults); + next = paging?.next?.after; + params.after = next; + params.limit = Math.min(100, this.maxResults - count); + } while (next && count < this.maxResults);Also applies to: 24-25, 43-45
components/hubspot/sources/new-note/new-note.mjs (1)
36-41: Bug: possible TypeError when spreadingcustomObjectsWhen
listSchemas()returns noresults,customisundefined, socustomObjectsbecomesundefined. Spreading...customObjectswill throw. Default to[].- const { results: custom } = await this.hubspot.listSchemas(); - const customObjects = custom?.map(({ fullyQualifiedName }) => fullyQualifiedName); + const { results: custom } = await this.hubspot.listSchemas(); + const customObjects = (custom || []).map(({ fullyQualifiedName }) => fullyQualifiedName); const associations = [ ...objectTypes, ...customObjects, ];components/hubspot/actions/list-marketing-emails/list-marketing-emails.mjs (2)
82-107: results is shadowed; you're pushing into the page array, not the accumulator (risk of runaway iteration) and returning an empty list.Use a distinct accumulator and rename the destructured page results.
Apply:
- const results = []; + const items = []; - const { - paging, results, - } = await this.hubspot.listMarketingEmails({ + const { + paging, results: pageResults, + } = await this.hubspot.listMarketingEmails({ - if (!results?.length) { + if (!pageResults?.length) { break; } - for (const item of results) { - results.push(item); + for (const item of pageResults) { + items.push(item); count++; if (count >= this.maxResults) { break; } } ... - $.export("$summary", `Found ${results.length} email${results.length === 1 + $.export("$summary", `Found ${items.length} email${items.length === 1 ? "" : "s"}`); - return results; + return items;Also applies to: 117-121
113-115: Optional chaining bug on paging.next.after.This will throw when paging.next is undefined; chain both accesses.
- hasMore = paging?.next.after; - params.after = paging?.next.after; + const nextAfter = paging?.next?.after; + hasMore = Boolean(nextAfter); + params.after = nextAfter;components/hubspot/actions/create-meeting/create-meeting.mjs (1)
87-93: Validate JSON input and required properties before calling the API.Currently JSON.parse errors surface as generic exceptions and required props aren’t enforced.
- const properties = objectProperties - ? typeof objectProperties === "string" - ? JSON.parse(objectProperties) - : objectProperties - : otherProperties; + let properties = otherProperties; + if (objectProperties) { + if (typeof objectProperties === "string") { + try { + properties = JSON.parse(objectProperties); + } catch (e) { + throw new ConfigurationError("Invalid JSON in `Meeting Properties`."); + } + } else { + properties = objectProperties; + } + } + const required = ["hs_meeting_title", "hs_meeting_body", "hs_meeting_start_time", "hs_meeting_end_time"]; + for (const key of required) { + if (!properties?.[key]) { + throw new ConfigurationError(`Missing required meeting property: ${key}`); + } + }Also applies to: 109-113
components/hubspot/actions/list-forms/list-forms.mjs (2)
26-49: Same accumulator/shadowing bug as emails action; fixes required.- const results = []; + const items = []; ... - const { - paging, results, + const { + paging, results: pageResults, } = await this.hubspot.listMarketingForms({ ... - if (!results?.length) { + if (!pageResults?.length) { break; } - for (const item of results) { - results.push(item); + for (const item of pageResults) { + items.push(item); count++; if (count >= this.maxResults) { break; } } ... - $.export("$summary", `Found ${results.length} form${results.length === 1 + $.export("$summary", `Found ${items.length} form${items.length === 1 ? "" : "s"}`); - return results; + return items;Also applies to: 54-58
50-52: Optional chaining bug on paging.next.after.Chain both accesses.
- hasMore = paging?.next.after; - params.after = paging?.next.after; + const nextAfter = paging?.next?.after; + hasMore = Boolean(nextAfter); + params.after = nextAfter;components/hubspot/actions/batch-create-or-update-contact/batch-create-or-update-contact.mjs (4)
29-33: Likely incorrect HubSpot object name ("contact" → "contacts").HubSpot search endpoint path is
/crm/v3/objects/contacts/search(plural). Inconsistent with other modules (e.g., companies uses plural). This will 404 or fail routing in the app client.- object: "contact", + object: "contacts",
27-44: Guard against undefined results and filter invalid emails.If search returns no results,
resultsisundefined, makingupdateEmails.includes(...)throw. Also,emailsmay include falsy values.- const emails = contacts.map(({ email }) => email); - const { results } = await this.hubspot.searchCRM({ + const emails = contacts.map(({ email }) => email).filter(Boolean); + const { results = [] } = await this.hubspot.searchCRM({ $, - object: "contact", + object: "contacts", data: { filters: [ { propertyName: "email", operator: "IN", values: emails, }, ], }, }); - const updateEmails = results?.map(({ properties }) => properties.email); - const insertProperties = contacts.filter(({ email }) => !updateEmails.includes(email)) + const updateEmails = results.map(({ properties }) => properties.email).filter(Boolean); + const insertProperties = contacts + .filter(({ email }) => email && !updateEmails.includes(email)) .map((properties) => ({ properties, }));
47-53: Avoid passingidinsidepropertieson update.
contacts.find(...)returns the full contact object. If it containsid, you’ll sendidboth at top-level and insideproperties. Strip it to prevent validation errors.- for (const contact of results) { - updateProperties.push({ - id: contact.id, - properties: contacts.find(({ email }) => contact.properties.email === email), - }); - } + for (const contact of results) { + const found = contacts.find(({ email }) => contact.properties.email === email) || {}; + const { id: _discard, ...props } = found; + updateProperties.push({ + id: contact.id, + properties: props, + }); + }
67-77: Duplicate updates possible — dedupe by id before calling batch update.A contact present in search results and also provided with explicit
idwill be pushed twice. HubSpot batch update may reject duplicate IDs.- if (updatePropertiesWithId?.length) { - updateProperties.push(...updatePropertiesWithId); - } + if (updatePropertiesWithId?.length) { + updateProperties.push(...updatePropertiesWithId); + } + // Dedupe updates by id + const byId = new Map(); + for (const u of updateProperties) { + const prev = byId.get(u.id); + byId.set(u.id, prev + ? { id: u.id, properties: { ...(prev.properties || {}), ...(u.properties || {}) } } + : u); + } + const uniqueUpdateProperties = Array.from(byId.values());And use
uniqueUpdatePropertiesbelow.components/hubspot/sources/new-deal-property-change/new-deal-property-change.mjs (1)
99-111: Bind thesearchCRMmethod to preserve its context ingetPaginatedItems. Without binding,thisinsidesearchCRMwill be undefined, leading to runtime errors.- const updatedDeals = await this.getPaginatedItems(this.hubspot.searchCRM, params); + const updatedDeals = await this.getPaginatedItems( + this.hubspot.searchCRM.bind(this.hubspot), + params, + );components/hubspot/actions/list-campaigns/list-campaigns.mjs (1)
41-60: Fix variable shadowing and self-extending iteration causing wrong results and potential infinite loop
- The destructured
resultsfrom the API shadows the outerresultsarray.- You then iterate the API
resultsand push into the same identifier, growing the array during iteration. This can cause iteration over newly appended items and, combined with shadowing, the outer array remains empty, leading to an incorrect summary/return.Apply this refactor to use distinct names and accumulate into a dedicated array:
- const results = []; + const items = []; let hasMore, count = 0; const params = { sort: this.sort, }; do { const { - paging, results, + paging, results: pageResults, } = await this.hubspot.listCampaigns({ $, params, }); - if (!results?.length) { + if (!pageResults?.length) { break; } - for (const item of results) { - results.push(item); + for (const item of pageResults) { + items.push(item); count++; if (count >= this.maxResults) { break; } } hasMore = paging?.next.after; params.after = paging?.next.after; - } while (hasMore && count < this.maxResults); + } while (hasMore && count < this.maxResults); - $.export("$summary", `Found ${results.length} campaign${results.length === 1 + $.export("$summary", `Found ${items.length} campaign${items.length === 1 ? "" : "s"}`); - return results; + return items;Also applies to: 34-35, 62-66, 37-39
components/hubspot/sources/delete-blog-article/delete-blog-article.mjs (1)
22-27: Use deleted timestamp consistently for event metadata
getTsreturnsdeletedAt, butgenerateMetasetstsfromcreated. This can mis-order events and confuse users.- const ts = Date.parse(blogpost.created); + const ts = this.getTs(blogpost); return { id: `${id}${this.getTs(blogpost)}`, summary, ts, };Also applies to: 14-16
components/hubspot/actions/get-file-public-url/get-file-public-url.mjs (2)
30-35: Fix possible TypeError when file isn’t found.Accessing
file.idbefore verifyingfilecan be undefined.Apply:
- const { results: files } = await this.hubspot.searchFiles(); - const file = files.find(({ url }) => url === fileUrl ); - const fileId = file.id; - if (!fileId) { - throw new Error(`File not found at ${fileUrl}`); - } + const { results: files } = await this.hubspot.searchFiles(); + const file = files.find(({ url }) => url === fileUrl); + if (!file?.id) { + throw new Error(`File not found at ${fileUrl}`); + } + const fileId = file.id;
18-23: Clamp expirationSeconds to API limits (1–21600).Prevents 400s and enforces documented bounds.
- const { - fileUrl, - expirationSeconds, - } = this; + const { fileUrl, expirationSeconds } = this; + const exp = Math.min(Math.max(Number(expirationSeconds ?? 3600), 1), 21600); @@ - params: { - expirationSeconds, - }, + params: { expirationSeconds: exp },Also applies to: 37-42
components/hubspot/sources/new-deal-in-stage/new-deal-in-stage.mjs (1)
36-43: Guard against missing version history.
properties.dealstage?.versions[0]will throw ifversionsis undefined.- return properties.dealstage?.versions[0].timestamp; + return properties.dealstage?.versions?.[0]?.timestamp ?? 0;components/hubspot/actions/batch-create-companies/batch-create-companies.mjs (1)
43-45: Harden error parsing; current logic can throw and hide root cause.Avoid double JSON.parse and regex splits on error strings.
- const message = JSON.parse((JSON.parse(error.message).message).split(/:(.+)/)[1])[0].message; - throw new ConfigurationError(message.split(/:(.+)/)[0]); + const message = + error?.response?.data?.errors?.[0]?.message || + error?.response?.data?.message || + error?.message; + throw new ConfigurationError(message);components/hubspot/sources/new-or-updated-line-item/new-or-updated-line-item.mjs (1)
80-82: Update searchCRM invocations to new object-style signature
- Replace every
await this.searchCRM(params, after)withawait this.searchCRM({ ...params, after })in all source files (e.g. new-ticket, new-or-updated-*, etc.) and adjust the wrapper in components/hubspot/sources/common/common.mjs accordingly.
Userg -nP '\bsearchCRM\s*\(' -g '*.mjs'to locate all call-sites.components/hubspot/sources/new-contact-property-change/new-contact-property-change.mjs (1)
102-103: Bind or wrapsearchCRMto preserve itsthiscontext
Without binding, callingthis.getPaginatedItems(this.hubspot.searchCRM, params)will lose the HubSpot app instance, breakingmakeRequestinsidesearchCRM. Replace with, for example:- const updatedContacts = await this.getPaginatedItems(this.hubspot.searchCRM, params); + const updatedContacts = await this.getPaginatedItems( + opts => this.hubspot.searchCRM(opts), + params, + );Or:
const updatedContacts = await this.getPaginatedItems( this.hubspot.searchCRM.bind(this.hubspot), params, );components/hubspot/sources/new-or-updated-product/new-or-updated-product.mjs (1)
83-85: Update allprocessResultscalls to match the newsearchCRMsignature
Replace every instance ofawait this.searchCRM(params, after);with
await this.searchCRM({ ...params, after });in the following files under
components/hubspot/sources/:
- new-ticket/new-ticket.mjs
- new-or-updated-line-item/new-or-updated-line-item.mjs
- new-or-updated-custom-object/new-or-updated-custom-object.mjs
- new-or-updated-product/new-or-updated-product.mjs
- new-or-updated-crm-object/new-or-updated-crm-object.mjs
- new-or-updated-contact/new-or-updated-contact.mjs
- new-or-updated-company/new-or-updated-company.mjs
- new-or-updated-deal/new-or-updated-deal.mjs
This ensures the
aftercursor is passed as part of the options object instead of a positional argument.components/hubspot/actions/list-pages/list-pages.mjs (1)
75-107: Bug: results variable shadowed; items pushed into the wrong array.Inner destructuring defines
resultsand you thenpushinto that local array instead of the outer accumulator, so you return an empty list. Also guardpaging?.next?.after.Apply:
async run({ $ }) { - const results = []; + const results = []; let hasMore, count = 0; @@ - do { - const { - paging, results, - } = await this.hubspot.listPages({ + do { + const { + paging, results: pageResults, + } = await this.hubspot.listPages({ $, params, }); - if (!results?.length) { + if (!pageResults?.length) { break; } - for (const item of results) { - results.push(item); + for (const item of pageResults) { + results.push(item); count++; if (count >= this.maxResults) { break; } } - hasMore = paging?.next.after; - params.after = paging?.next.after; + hasMore = paging?.next?.after; + params.after = hasMore; } while (hasMore && count < this.maxResults); @@ - $.export("$summary", `Found ${results.length} page${results.length === 1 + $.export("$summary", `Found ${results.length} page${results.length === 1 ? "" : "s"}`); return results;Also applies to: 110-114
components/hubspot/actions/list-blog-posts/list-blog-posts.mjs (1)
75-107: Bug: same results-shadowing issue as list-pages.Local
resultsfrom the API shadows the accumulator, so nothing is returned.Apply:
async run({ $ }) { - const results = []; + const results = []; let hasMore, count = 0; @@ - do { - const { - paging, results, - } = await this.hubspot.getBlogPosts({ + do { + const { + paging, results: pageResults, + } = await this.hubspot.getBlogPosts({ $, params, }); - if (!results?.length) { + if (!pageResults?.length) { break; } - for (const item of results) { - results.push(item); + for (const item of pageResults) { + results.push(item); count++; if (count >= this.maxResults) { break; } } - hasMore = paging?.next.after; - params.after = paging?.next.after; + hasMore = paging?.next?.after; + params.after = hasMore; } while (hasMore && count < this.maxResults);Also applies to: 110-114
components/hubspot/actions/create-communication/create-communication.mjs (1)
76-81: Harden JSON parsing for objectProperties.Invalid JSON will throw a generic error. Wrap in try/catch and surface a
ConfigurationErrorwith a clear message.- const properties = objectProperties - ? typeof objectProperties === "string" - ? JSON.parse(objectProperties) - : objectProperties - : otherProperties; + let properties = otherProperties; + if (objectProperties) { + if (typeof objectProperties === "string") { + try { + properties = JSON.parse(objectProperties); + } catch (err) { + throw new ConfigurationError("Invalid JSON in `objectProperties`"); + } + } else { + properties = objectProperties; + } + }components/hubspot/actions/get-associated-emails/get-associated-emails.mjs (2)
71-74: Bug: incorrect emptiness check due to operator precedence.
if (!results?.length > 0)always evaluates unexpectedly. Use a direct length check.- if (!results?.length > 0) { + if (!results?.length) { $.export("$summary", "No emails found with this association"); return []; }
80-95: Robustness: default to empty array and simplify sorting.Avoid
emailsbeingundefinedand remove the|| []no-op.- const { results: emails } = await this.hubspot.batchGetObjects({ + const { results: emails = [] } = await this.hubspot.batchGetObjects({ $, objectType: "emails", data: { properties, inputs: emailIds, }, }); - // Sort emails by timestamp in descending order (most recent first) - emails?.sort((a, b) => { + // Sort emails by timestamp in descending order (most recent first) + emails.sort((a, b) => { const timestampA = new Date(a.properties?.hs_timestamp || 0).getTime(); const timestampB = new Date(b.properties?.hs_timestamp || 0).getTime(); return timestampB - timestampA; - }) || []; + }); const summary = `Successfully retrieved ${emails.length} email(s)`; $.export("$summary", summary); return emails;Also applies to: 96-101
🧹 Nitpick comments (15)
components/hubspot/sources/new-note/new-note.mjs (1)
16-18: Optional: guard against missing/invalid timestamps
Date.parse(note.createdAt)can returnNaN. Consider a fallback (e.g.,updatedAt) or filter out invalid notes.- getTs(note) { - return Date.parse(note.createdAt); - }, + getTs(note) { + const ts = Date.parse(note.createdAt); + return Number.isNaN(ts) ? 0 : ts; + },Also applies to: 26-28
components/hubspot/sources/new-or-updated-crm-object/new-or-updated-crm-object.mjs (1)
43-45: Use strict equality; avoid coercion.Minor, but improves correctness/readability.
- const propertyName = (object == "contacts") + const propertyName = (object === "contacts") ? "lastmodifieddate" : "hs_lastmodifieddate"; ... - const object = (this.objectType == "company") + const object = (this.objectType === "company") ? "companies" : `${this.objectType}s`;Also applies to: 60-63
components/hubspot/actions/batch-create-or-update-contact/batch-create-or-update-contact.mjs (3)
79-92: Skip empty batch calls and use deduped arrays.Avoid issuing API calls with empty inputs; also ensure you use the deduped updates.
- response.created = await this.hubspot.batchCreateContacts({ - $, - data: { - inputs: insertProperties, - }, - }); - response.updated = await this.hubspot.batchUpdateContacts({ - $, - data: { - inputs: updateProperties, - }, - }); + response.created = insertProperties.length + ? await this.hubspot.batchCreateContacts({ $, data: { inputs: insertProperties } }) + : { results: [] }; + response.updated = uniqueUpdateProperties?.length + ? await this.hubspot.batchUpdateContacts({ $, data: { inputs: uniqueUpdateProperties } }) + : { results: [] };
93-95: Fix summary counts after dedupe and conditional calls.Use the arrays actually sent to the API.
- $.export("$summary", `Successfully created ${insertProperties.length} and updated ${updateProperties.length} contacts`); + $.export("$summary", `Successfully created ${insertProperties.length} and updated ${uniqueUpdateProperties?.length || 0} contacts`);
18-26: Input validation for contacts schema (optional).Consider validating required fields (e.g., email for create; id or email for update) and max batch sizes to reduce 429s even with the new retry/backoff.
Do you want a zod/Yup-based validator and chunking helper (e.g., size 100) to align with HubSpot limits?
components/hubspot/actions/batch-update-companies/batch-update-companies.mjs (1)
43-45: Harden error parsing to avoid double-parse crashes.JSON.parse on nested messages can throw and mask original errors. Guard parsing and fall back to raw message.
- const message = JSON.parse((JSON.parse(error.message).message).split(/:(.+)/)[1])[0].message; - throw new ConfigurationError(message.split(/:(.+)/)[0]); + let msg = error?.message; + try { + const outer = JSON.parse(msg); + const inner = typeof outer?.message === "string" ? outer.message : ""; + const sliced = inner.split(/:(.+)/)[1]; + const arr = JSON.parse(sliced || "[]"); + msg = (arr?.[0]?.message || inner || msg).split(/:(.+)/)[0]; + } catch (_) { + /* keep original msg */ + } + throw new ConfigurationError(msg);components/hubspot/sources/new-event/new-event.mjs (1)
10-12: Version bump OK; fix brand capitalization in description.Only metadata changed. Please update “Hubspot” → “HubSpot” in the user-facing description.
- description: "Emit new event for each new Hubspot event. Note: Only available for Marketing Hub Enterprise, Sales Hub Enterprise, Service Hub Enterprise, or CMS Hub Enterprise accounts", + description: "Emit new event for each new HubSpot event. Note: Only available for Marketing Hub Enterprise, Sales Hub Enterprise, Service Hub Enterprise, or CMS Hub Enterprise accounts",components/hubspot/actions/create-deal/create-deal.mjs (1)
8-10: Version bump OK; fix brand capitalization in description.Update “Hubspot” → “HubSpot”.
- description: "Create a deal in Hubspot. [See the documentation](https://developers.hubspot.com/docs/api/crm/deals#endpoint?spec=POST-/crm/v3/objects/deals)", + description: "Create a deal in HubSpot. [See the documentation](https://developers.hubspot.com/docs/api/crm/deals#endpoint?spec=POST-/crm/v3/objects/deals)",components/hubspot/actions/list-campaigns/list-campaigns.mjs (2)
37-39: Avoid sending undefined query paramsOnly include
sortwhen provided to keep requests clean and reduce chance of API-side validation noise.- const params = { - sort: this.sort, - }; + const params = {}; + if (this.sort) params.sort = this.sort;
7-7: Version bump looks goodMetadata bump to 0.0.2 is fine. Please include a short changelog entry referencing the HubSpot rate-limit adjustments in hubspot.app.mjs for traceability.
components/hubspot/sources/delete-blog-article/delete-blog-article.mjs (1)
29-36: Consider sorting by deleted timeFor a deleted-posts source, sorting by
-deletedAtlikely matches user expectations better than-updatedAt. Review API support and adjust if available.components/hubspot/sources/new-deal-in-stage/new-deal-in-stage.mjs (1)
100-106: Avoid repeated owner lookups; memoize.This loop fetches the same owner multiple times.
- if (deal.properties.hubspot_owner_id) { - deal.properties.owner = await this.getOwner(deal.properties.hubspot_owner_id); - } + if (deal.properties.hubspot_owner_id) { + deal.properties.owner = await this.getOwnerCached(deal.properties.hubspot_owner_id); + }Add once under
methods:ownerCache: new Map(), async getOwnerCached(ownerId) { if (!this.ownerCache.has(ownerId)) { this.ownerCache.set(ownerId, await this.getOwner(ownerId)); } return this.ownerCache.get(ownerId); }components/hubspot/hubspot.app.mjs (3)
18-18: Global rate limit halved to 2 rps — verify impact.
This affects all HubSpot endpoints, not just search. Confirm no noticeable throughput regressions for non-search actions/sources. Consider keeping minTime at 250 ms and applying a dedicated limiter just for the search endpoint if needed.
697-725: Add minimal observability for retries.
Log attempt count and delay (when available) to aid support/debugging under rate limit pressure. Use$from opts if present; otherwise skip.Example (inline within the retry branch after computing
delay):+ const $ = opts?.$; + if ($ && typeof $.log === "function") { + $.log(`HubSpot searchCRM 429: retrying attempt ${attempt + 1}/${MAX_ATTEMPTS} in ${delay}ms`); + }
18-18: Architecture: consider endpoint-scoped limiter.
If non-search endpoints suffer from the stricter global rate, introduce a separate Bottleneck instance just for/searchrequests (e.g., 500 ms) and keep the global limiter at 250 ms for others.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (65)
components/hubspot/actions/add-contact-to-list/add-contact-to-list.mjs(1 hunks)components/hubspot/actions/batch-create-companies/batch-create-companies.mjs(1 hunks)components/hubspot/actions/batch-create-or-update-contact/batch-create-or-update-contact.mjs(1 hunks)components/hubspot/actions/batch-update-companies/batch-update-companies.mjs(1 hunks)components/hubspot/actions/batch-upsert-companies/batch-upsert-companies.mjs(1 hunks)components/hubspot/actions/create-associations/create-associations.mjs(1 hunks)components/hubspot/actions/create-communication/create-communication.mjs(1 hunks)components/hubspot/actions/create-company/create-company.mjs(1 hunks)components/hubspot/actions/create-custom-object/create-custom-object.mjs(1 hunks)components/hubspot/actions/create-deal/create-deal.mjs(1 hunks)components/hubspot/actions/create-engagement/create-engagement.mjs(1 hunks)components/hubspot/actions/create-lead/create-lead.mjs(1 hunks)components/hubspot/actions/create-meeting/create-meeting.mjs(1 hunks)components/hubspot/actions/create-note/create-note.mjs(1 hunks)components/hubspot/actions/create-or-update-contact/create-or-update-contact.mjs(1 hunks)components/hubspot/actions/create-task/create-task.mjs(1 hunks)components/hubspot/actions/create-ticket/create-ticket.mjs(1 hunks)components/hubspot/actions/enroll-contact-into-workflow/enroll-contact-into-workflow.mjs(1 hunks)components/hubspot/actions/get-associated-emails/get-associated-emails.mjs(1 hunks)components/hubspot/actions/get-associated-meetings/get-associated-meetings.mjs(1 hunks)components/hubspot/actions/get-company/get-company.mjs(1 hunks)components/hubspot/actions/get-contact/get-contact.mjs(1 hunks)components/hubspot/actions/get-deal/get-deal.mjs(1 hunks)components/hubspot/actions/get-file-public-url/get-file-public-url.mjs(1 hunks)components/hubspot/actions/get-meeting/get-meeting.mjs(1 hunks)components/hubspot/actions/get-subscription-preferences/get-subscription-preferences.mjs(1 hunks)components/hubspot/actions/list-blog-posts/list-blog-posts.mjs(1 hunks)components/hubspot/actions/list-campaigns/list-campaigns.mjs(1 hunks)components/hubspot/actions/list-forms/list-forms.mjs(1 hunks)components/hubspot/actions/list-marketing-emails/list-marketing-emails.mjs(1 hunks)components/hubspot/actions/list-marketing-events/list-marketing-events.mjs(1 hunks)components/hubspot/actions/list-pages/list-pages.mjs(1 hunks)components/hubspot/actions/list-templates/list-templates.mjs(1 hunks)components/hubspot/actions/search-crm/search-crm.mjs(1 hunks)components/hubspot/actions/update-company/update-company.mjs(1 hunks)components/hubspot/actions/update-contact/update-contact.mjs(1 hunks)components/hubspot/actions/update-custom-object/update-custom-object.mjs(1 hunks)components/hubspot/actions/update-deal/update-deal.mjs(1 hunks)components/hubspot/actions/update-lead/update-lead.mjs(1 hunks)components/hubspot/hubspot.app.mjs(2 hunks)components/hubspot/package.json(1 hunks)components/hubspot/sources/delete-blog-article/delete-blog-article.mjs(1 hunks)components/hubspot/sources/new-company-property-change/new-company-property-change.mjs(1 hunks)components/hubspot/sources/new-contact-property-change/new-contact-property-change.mjs(1 hunks)components/hubspot/sources/new-custom-object-property-change/new-custom-object-property-change.mjs(1 hunks)components/hubspot/sources/new-deal-in-stage/new-deal-in-stage.mjs(1 hunks)components/hubspot/sources/new-deal-property-change/new-deal-property-change.mjs(1 hunks)components/hubspot/sources/new-email-event/new-email-event.mjs(1 hunks)components/hubspot/sources/new-email-subscriptions-timeline/new-email-subscriptions-timeline.mjs(1 hunks)components/hubspot/sources/new-engagement/new-engagement.mjs(1 hunks)components/hubspot/sources/new-event/new-event.mjs(1 hunks)components/hubspot/sources/new-form-submission/new-form-submission.mjs(1 hunks)components/hubspot/sources/new-note/new-note.mjs(1 hunks)components/hubspot/sources/new-or-updated-blog-article/new-or-updated-blog-article.mjs(1 hunks)components/hubspot/sources/new-or-updated-company/new-or-updated-company.mjs(1 hunks)components/hubspot/sources/new-or-updated-contact/new-or-updated-contact.mjs(1 hunks)components/hubspot/sources/new-or-updated-crm-object/new-or-updated-crm-object.mjs(1 hunks)components/hubspot/sources/new-or-updated-custom-object/new-or-updated-custom-object.mjs(1 hunks)components/hubspot/sources/new-or-updated-deal/new-or-updated-deal.mjs(1 hunks)components/hubspot/sources/new-or-updated-line-item/new-or-updated-line-item.mjs(1 hunks)components/hubspot/sources/new-or-updated-product/new-or-updated-product.mjs(1 hunks)components/hubspot/sources/new-social-media-message/new-social-media-message.mjs(1 hunks)components/hubspot/sources/new-task/new-task.mjs(1 hunks)components/hubspot/sources/new-ticket-property-change/new-ticket-property-change.mjs(1 hunks)components/hubspot/sources/new-ticket/new-ticket.mjs(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
components/hubspot/hubspot.app.mjs (1)
components/hubspot/common/constants.mjs (1)
API_PATH(9-28)
⏰ 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). (4)
- GitHub Check: Verify TypeScript components
- GitHub Check: Publish TypeScript components
- GitHub Check: pnpm publish
- GitHub Check: Lint Code Base
🔇 Additional comments (62)
components/hubspot/sources/new-form-submission/new-form-submission.mjs (1)
9-9: Version bump only — LGTM.No functional impact detected here.
components/hubspot/actions/update-custom-object/update-custom-object.mjs (1)
9-9: Version bump only — LGTM.No behavior change in this action.
components/hubspot/sources/new-task/new-task.mjs (1)
11-11: Version bump only — LGTM.No runtime changes observed.
components/hubspot/actions/create-associations/create-associations.mjs (1)
8-8: Version bump only — LGTM.Action logic unchanged.
components/hubspot/actions/get-company/get-company.mjs (1)
9-9: Version bump only — LGTM.No functional differences.
components/hubspot/actions/list-marketing-events/list-marketing-events.mjs (1)
7-7: Version bump only — OKMetadata update looks fine.
components/hubspot/sources/new-note/new-note.mjs (1)
11-11: Version bump only — OKNo functional changes in this file.
components/hubspot/actions/update-deal/update-deal.mjs (1)
10-10: Version bump only — OKNo logic changes detected.
components/hubspot/actions/create-ticket/create-ticket.mjs (1)
9-9: Version bump only — OKNo functional modifications.
components/hubspot/actions/get-deal/get-deal.mjs (1)
9-9: Version bump only — OKLooks good.
components/hubspot/actions/list-marketing-emails/list-marketing-emails.mjs (1)
7-7: Version bump only — OK.components/hubspot/actions/create-meeting/create-meeting.mjs (1)
13-13: Version bump only — OK.components/hubspot/actions/get-contact/get-contact.mjs (1)
9-9: Version bump only — OK.components/hubspot/actions/list-forms/list-forms.mjs (1)
7-7: Version bump only — OK.components/hubspot/actions/create-custom-object/create-custom-object.mjs (1)
9-9: Version bump only — OK.No behavioral changes. Safe to merge.
components/hubspot/sources/new-or-updated-company/new-or-updated-company.mjs (2)
12-12: Version bump only — OK.No logic changes in this source.
84-85: All searchCRM invocations are properly awaited. Only the method definitions themselves (in hubspot.app.mjs and common.mjs) appear withoutawait.components/hubspot/sources/new-email-event/new-email-event.mjs (1)
11-11: Version bump only — OK.No runtime changes.
components/hubspot/actions/batch-create-or-update-contact/batch-create-or-update-contact.mjs (1)
29-41: searchCRM is properly rate-limited and retry/backoff meets 2 RPS and ~17 s budget. The Bottleneck limiter (minTime = 500 ms) wraps all makeRequest calls, and searchCRM’s exponential backoff (5 attempts, delays 1–1.5 s, 2–2.5 s, 4–4.5 s, 8–8.5 s) caps at ~17 s total.components/hubspot/actions/update-contact/update-contact.mjs (1)
10-10: Version bump only — OK.No behavior change.
components/hubspot/actions/batch-update-companies/batch-update-companies.mjs (1)
10-10: Version bump is fine.Metadata-only change; no runtime impact here.
components/hubspot/sources/new-deal-property-change/new-deal-property-change.mjs (1)
10-10: Version bump looks good.components/hubspot/actions/update-company/update-company.mjs (1)
10-10: OK to ship.Patch version bump only.
components/hubspot/actions/add-contact-to-list/add-contact-to-list.mjs (1)
7-7: LGTM on version bump.components/hubspot/actions/create-engagement/create-engagement.mjs (1)
12-12: Version increment acknowledged.components/hubspot/sources/new-social-media-message/new-social-media-message.mjs (1)
9-10: LGTM on version bump.No functional changes in this file.
components/hubspot/sources/new-or-updated-deal/new-or-updated-deal.mjs (1)
11-13: Verify searchCRM signature & fix HubSpot branding
- Confirm
this.searchCRM(params, after)matches the updated retry signature and that retries don’t break dedupe/order.- Honor any
Retry-Afterheader on 429 responses, within the 17 s cap.- Rename “Hubspot” → “HubSpot” in the description.
- description: "Emit new event for each new or updated deal in Hubspot", + description: "Emit new event for each new or updated deal in HubSpot",components/hubspot/sources/new-ticket/new-ticket.mjs (2)
72-75: ConfirmsearchCRMsignature remains(params, after)post-retry changesYou’re awaiting
this.searchCRM(params, after)which is good given the new async + retry behavior. Please verify the method’s parameter order didn’t change inhubspot.app.mjsduring the retry work.
12-12: Version bump acknowledgedNo functional changes detected in this source; version 0.0.26 is fine.
components/hubspot/sources/delete-blog-article/delete-blog-article.mjs (1)
9-9: Version bump looks fine0.0.26 acknowledged; no other behavioral changes here.
components/hubspot/actions/create-lead/create-lead.mjs (1)
12-12: Version bump only — OKNo runtime or API-surface changes detected; 0.0.12 metadata bump is fine.
components/hubspot/actions/create-task/create-task.mjs (1)
10-10: Version bump only — OKNo logic changes; 0.0.5 acknowledged.
components/hubspot/sources/new-custom-object-property-change/new-custom-object-property-change.mjs (1)
9-9: Version bump LGTM; searchCRM remains compatible with getPaginatedItems
No changes required—hubspot.app.searchCRM still returns{ results, paging }and accepts a singleparamsobject (which includesobject), sogetPaginatedItems(this.hubspot.searchCRM, params)continues to work as before.components/hubspot/sources/new-ticket-property-change/new-ticket-property-change.mjs (1)
10-10: Confirm 429 retry onsearchCRMpreservesgetPaginatedItemspagination semanticsThis source calls
getPaginatedItems(this.hubspot.searchCRM, params)(new-ticket-property-change.mjs line 103). Manually verify that the added 429-retry logic doesn’t change the returned item array or paging loop.components/hubspot/actions/enroll-contact-into-workflow/enroll-contact-into-workflow.mjs (1)
7-7: LGTM on version bump.No functional changes; action path unaffected by search retry updates.
components/hubspot/actions/get-meeting/get-meeting.mjs (1)
9-9: LGTM on version bump.No behavior changes detected.
components/hubspot/sources/new-or-updated-blog-article/new-or-updated-blog-article.mjs (1)
10-10: LGTM on version bump.No logic changes; source should be unaffected by the global limiter tweak.
components/hubspot/actions/create-note/create-note.mjs (1)
10-10: LGTM: metadata-only bump.No runtime changes here; nothing further from the retry/RPS adjustments impacts this action.
components/hubspot/actions/create-company/create-company.mjs (1)
9-9: LGTM: version bump only.No coupling to searchCRM; safe.
components/hubspot/actions/get-associated-meetings/get-associated-meetings.mjs (1)
9-9: Version bump verified; searchCRM signature unchanged
Allhubspot.searchCRMcalls—including inget-associated-meetings—accept the same{ object, data }shape used elsewhere. The retry/backoff update adds no new required options.components/hubspot/actions/batch-upsert-companies/batch-upsert-companies.mjs (1)
10-10: LGTM: version bump only.No interaction with the updated rate limiter or search retries.
components/hubspot/actions/get-file-public-url/get-file-public-url.mjs (1)
7-7: LGTM – version bump only.components/hubspot/sources/new-deal-in-stage/new-deal-in-stage.mjs (2)
12-12: LGTM – version bump only.
92-99: All.searchCRMinvocations are properly awaited. Verified via code search that every call tosearchCRM(is preceded byawait.components/hubspot/actions/batch-create-companies/batch-create-companies.mjs (1)
10-10: LGTM – version bump only.components/hubspot/actions/get-subscription-preferences/get-subscription-preferences.mjs (1)
7-7: LGTM – version bump only.components/hubspot/actions/update-lead/update-lead.mjs (1)
10-10: LGTM – version bump only.components/hubspot/sources/new-or-updated-line-item/new-or-updated-line-item.mjs (1)
12-12: Version bump aligns with HubSpot search retry rolloutNo issues with the metadata change.
components/hubspot/actions/list-templates/list-templates.mjs (1)
7-7: Version bump only — looks goodNo functional changes detected.
components/hubspot/sources/new-contact-property-change/new-contact-property-change.mjs (1)
10-10: Version bump matches package patch updateNo functional impact here.
components/hubspot/actions/create-or-update-contact/create-or-update-contact.mjs (1)
9-9: Version bump only — OKNo action needed.
components/hubspot/sources/new-or-updated-product/new-or-updated-product.mjs (1)
12-12: Version bump consistent with module setLooks good.
components/hubspot/actions/list-pages/list-pages.mjs (1)
7-7: Patch version bump looks good.Consistent with package patch bump and non-functional changes here.
components/hubspot/actions/list-blog-posts/list-blog-posts.mjs (1)
7-7: Patch version bump is appropriate.No behavior change in this file; aligns with app-level limiter/retry updates.
components/hubspot/package.json (1)
3-3: Package patch bump matches the scope of changes.1.6.1 is appropriate for limiter + retry tweaks without breaking APIs.
components/hubspot/actions/create-communication/create-communication.mjs (1)
11-11: Version bump OK.components/hubspot/actions/get-associated-emails/get-associated-emails.mjs (1)
8-8: Patch version bump looks fine.components/hubspot/sources/new-engagement/new-engagement.mjs (1)
11-11: Version bump only — LGTM.components/hubspot/sources/new-or-updated-custom-object/new-or-updated-custom-object.mjs (1)
10-10: Version bump only — LGTM.components/hubspot/sources/new-email-subscriptions-timeline/new-email-subscriptions-timeline.mjs (1)
9-9: Version bump only — LGTM.components/hubspot/actions/search-crm/search-crm.mjs (1)
20-20: Version bump only — LGTM.components/hubspot/hubspot.app.mjs (1)
697-725: searchCRM call sites align with new signature – all invocations use eitherthis.searchCRM(params, after)(wrapper) or directthis.hubspot.searchCRM({ object, … }); no string/legacy signatures remain. Manually confirm that theparamsobject in new-deal-in-stage includes the requiredobjectfield.
components/hubspot/actions/create-associations/create-associations.mjs
Outdated
Show resolved
Hide resolved
components/hubspot/sources/new-or-updated-contact/new-or-updated-contact.mjs
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
components/hubspot/actions/list-campaigns/list-campaigns.mjs (1)
34-61: Fix variable shadowing and self-append bug (returns empty array, may iterate indefinitely)
- Outer
resultsaccumulator is shadowed by{ results }from the API response.- Inside the loop you push into the same array you’re iterating (
for ... of results+results.push(item)), which can extend iteration and never populate the accumulator.- Summary/return then use the (never-filled) outer
results.Apply this patch:
- const results = []; - let hasMore, count = 0; + const items = []; + let after; + let count = 0; @@ - const params = { - sort: this.sort, - }; + const params = {}; + if (this.sort) params.sort = this.sort; @@ - const { - paging, results, - } = await this.hubspot.listCampaigns({ + if (after) params.after = after; + else delete params.after; + const { + paging, results: pageResults, + } = await this.hubspot.listCampaigns({ $, params, }); - if (!results?.length) { + if (!pageResults?.length) { break; } - for (const item of results) { - results.push(item); + for (const item of pageResults) { + items.push(item); count++; if (count >= this.maxResults) { break; } } - hasMore = paging?.next.after; - params.after = paging?.next.after; - } while (hasMore && count < this.maxResults); + after = paging?.next?.after; + } while (after && count < this.maxResults); @@ - $.export("$summary", `Found ${results.length} campaign${results.length === 1 + $.export("$summary", `Found ${items.length} campaign${items.length === 1 ? "" : "s"}`); - return results; + return items;
🧹 Nitpick comments (1)
components/hubspot/actions/list-campaigns/list-campaigns.mjs (1)
45-47: Optional: request larger page sizes to reduce callsIf the HubSpot endpoint supports a
limit/pageSizeparameter, passmin(remaining, maxSupported)per request to cut round-trips under rate limits.Can you confirm the correct page-size param name for
marketing/v3/campaignsand the max allowed value? If supported, I can provide a follow-up patch.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (63)
components/hubspot/actions/add-contact-to-list/add-contact-to-list.mjs(1 hunks)components/hubspot/actions/batch-create-companies/batch-create-companies.mjs(1 hunks)components/hubspot/actions/batch-create-or-update-contact/batch-create-or-update-contact.mjs(1 hunks)components/hubspot/actions/batch-update-companies/batch-update-companies.mjs(1 hunks)components/hubspot/actions/batch-upsert-companies/batch-upsert-companies.mjs(1 hunks)components/hubspot/actions/create-associations/create-associations.mjs(1 hunks)components/hubspot/actions/create-communication/create-communication.mjs(1 hunks)components/hubspot/actions/create-company/create-company.mjs(1 hunks)components/hubspot/actions/create-custom-object/create-custom-object.mjs(1 hunks)components/hubspot/actions/create-deal/create-deal.mjs(1 hunks)components/hubspot/actions/create-engagement/create-engagement.mjs(1 hunks)components/hubspot/actions/create-lead/create-lead.mjs(1 hunks)components/hubspot/actions/create-meeting/create-meeting.mjs(1 hunks)components/hubspot/actions/create-note/create-note.mjs(1 hunks)components/hubspot/actions/create-or-update-contact/create-or-update-contact.mjs(1 hunks)components/hubspot/actions/create-task/create-task.mjs(1 hunks)components/hubspot/actions/create-ticket/create-ticket.mjs(1 hunks)components/hubspot/actions/enroll-contact-into-workflow/enroll-contact-into-workflow.mjs(1 hunks)components/hubspot/actions/get-associated-emails/get-associated-emails.mjs(1 hunks)components/hubspot/actions/get-associated-meetings/get-associated-meetings.mjs(1 hunks)components/hubspot/actions/get-company/get-company.mjs(1 hunks)components/hubspot/actions/get-contact/get-contact.mjs(1 hunks)components/hubspot/actions/get-deal/get-deal.mjs(1 hunks)components/hubspot/actions/get-file-public-url/get-file-public-url.mjs(1 hunks)components/hubspot/actions/get-meeting/get-meeting.mjs(1 hunks)components/hubspot/actions/get-subscription-preferences/get-subscription-preferences.mjs(1 hunks)components/hubspot/actions/list-blog-posts/list-blog-posts.mjs(1 hunks)components/hubspot/actions/list-campaigns/list-campaigns.mjs(1 hunks)components/hubspot/actions/list-forms/list-forms.mjs(1 hunks)components/hubspot/actions/list-marketing-emails/list-marketing-emails.mjs(1 hunks)components/hubspot/actions/list-marketing-events/list-marketing-events.mjs(1 hunks)components/hubspot/actions/list-pages/list-pages.mjs(1 hunks)components/hubspot/actions/list-templates/list-templates.mjs(1 hunks)components/hubspot/actions/search-crm/search-crm.mjs(1 hunks)components/hubspot/actions/update-company/update-company.mjs(1 hunks)components/hubspot/actions/update-contact/update-contact.mjs(1 hunks)components/hubspot/actions/update-custom-object/update-custom-object.mjs(1 hunks)components/hubspot/actions/update-deal/update-deal.mjs(1 hunks)components/hubspot/actions/update-lead/update-lead.mjs(1 hunks)components/hubspot/sources/delete-blog-article/delete-blog-article.mjs(1 hunks)components/hubspot/sources/new-company-property-change/new-company-property-change.mjs(1 hunks)components/hubspot/sources/new-contact-property-change/new-contact-property-change.mjs(1 hunks)components/hubspot/sources/new-custom-object-property-change/new-custom-object-property-change.mjs(1 hunks)components/hubspot/sources/new-deal-in-stage/new-deal-in-stage.mjs(1 hunks)components/hubspot/sources/new-deal-property-change/new-deal-property-change.mjs(1 hunks)components/hubspot/sources/new-email-event/new-email-event.mjs(1 hunks)components/hubspot/sources/new-email-subscriptions-timeline/new-email-subscriptions-timeline.mjs(1 hunks)components/hubspot/sources/new-engagement/new-engagement.mjs(1 hunks)components/hubspot/sources/new-event/new-event.mjs(1 hunks)components/hubspot/sources/new-form-submission/new-form-submission.mjs(1 hunks)components/hubspot/sources/new-note/new-note.mjs(1 hunks)components/hubspot/sources/new-or-updated-blog-article/new-or-updated-blog-article.mjs(1 hunks)components/hubspot/sources/new-or-updated-company/new-or-updated-company.mjs(1 hunks)components/hubspot/sources/new-or-updated-contact/new-or-updated-contact.mjs(1 hunks)components/hubspot/sources/new-or-updated-crm-object/new-or-updated-crm-object.mjs(1 hunks)components/hubspot/sources/new-or-updated-custom-object/new-or-updated-custom-object.mjs(1 hunks)components/hubspot/sources/new-or-updated-deal/new-or-updated-deal.mjs(1 hunks)components/hubspot/sources/new-or-updated-line-item/new-or-updated-line-item.mjs(1 hunks)components/hubspot/sources/new-or-updated-product/new-or-updated-product.mjs(1 hunks)components/hubspot/sources/new-social-media-message/new-social-media-message.mjs(1 hunks)components/hubspot/sources/new-task/new-task.mjs(1 hunks)components/hubspot/sources/new-ticket-property-change/new-ticket-property-change.mjs(1 hunks)components/hubspot/sources/new-ticket/new-ticket.mjs(1 hunks)
✅ Files skipped from review due to trivial changes (60)
- components/hubspot/sources/new-or-updated-blog-article/new-or-updated-blog-article.mjs
- components/hubspot/actions/create-note/create-note.mjs
- components/hubspot/sources/new-company-property-change/new-company-property-change.mjs
- components/hubspot/sources/new-or-updated-product/new-or-updated-product.mjs
- components/hubspot/actions/create-deal/create-deal.mjs
- components/hubspot/actions/batch-create-or-update-contact/batch-create-or-update-contact.mjs
- components/hubspot/actions/get-file-public-url/get-file-public-url.mjs
- components/hubspot/actions/search-crm/search-crm.mjs
- components/hubspot/actions/list-marketing-events/list-marketing-events.mjs
- components/hubspot/actions/create-engagement/create-engagement.mjs
- components/hubspot/sources/new-event/new-event.mjs
- components/hubspot/sources/new-note/new-note.mjs
- components/hubspot/sources/new-or-updated-crm-object/new-or-updated-crm-object.mjs
- components/hubspot/actions/update-contact/update-contact.mjs
- components/hubspot/actions/get-associated-emails/get-associated-emails.mjs
- components/hubspot/sources/new-social-media-message/new-social-media-message.mjs
- components/hubspot/actions/create-company/create-company.mjs
- components/hubspot/actions/batch-create-companies/batch-create-companies.mjs
- components/hubspot/actions/create-lead/create-lead.mjs
- components/hubspot/sources/new-email-subscriptions-timeline/new-email-subscriptions-timeline.mjs
- components/hubspot/actions/batch-update-companies/batch-update-companies.mjs
- components/hubspot/actions/list-pages/list-pages.mjs
- components/hubspot/actions/get-contact/get-contact.mjs
- components/hubspot/actions/list-blog-posts/list-blog-posts.mjs
- components/hubspot/actions/get-company/get-company.mjs
- components/hubspot/actions/add-contact-to-list/add-contact-to-list.mjs
- components/hubspot/sources/delete-blog-article/delete-blog-article.mjs
- components/hubspot/sources/new-or-updated-deal/new-or-updated-deal.mjs
- components/hubspot/actions/enroll-contact-into-workflow/enroll-contact-into-workflow.mjs
- components/hubspot/actions/get-associated-meetings/get-associated-meetings.mjs
- components/hubspot/actions/update-custom-object/update-custom-object.mjs
- components/hubspot/sources/new-deal-in-stage/new-deal-in-stage.mjs
- components/hubspot/sources/new-deal-property-change/new-deal-property-change.mjs
- components/hubspot/sources/new-contact-property-change/new-contact-property-change.mjs
- components/hubspot/sources/new-or-updated-custom-object/new-or-updated-custom-object.mjs
- components/hubspot/sources/new-email-event/new-email-event.mjs
- components/hubspot/actions/list-templates/list-templates.mjs
- components/hubspot/actions/list-forms/list-forms.mjs
- components/hubspot/sources/new-or-updated-line-item/new-or-updated-line-item.mjs
- components/hubspot/actions/update-lead/update-lead.mjs
- components/hubspot/actions/get-subscription-preferences/get-subscription-preferences.mjs
- components/hubspot/sources/new-engagement/new-engagement.mjs
- components/hubspot/actions/create-task/create-task.mjs
- components/hubspot/sources/new-or-updated-company/new-or-updated-company.mjs
- components/hubspot/actions/update-deal/update-deal.mjs
- components/hubspot/actions/batch-upsert-companies/batch-upsert-companies.mjs
- components/hubspot/sources/new-or-updated-contact/new-or-updated-contact.mjs
- components/hubspot/actions/create-ticket/create-ticket.mjs
- components/hubspot/actions/create-or-update-contact/create-or-update-contact.mjs
- components/hubspot/actions/get-meeting/get-meeting.mjs
- components/hubspot/sources/new-task/new-task.mjs
- components/hubspot/actions/create-associations/create-associations.mjs
- components/hubspot/actions/create-communication/create-communication.mjs
- components/hubspot/sources/new-form-submission/new-form-submission.mjs
- components/hubspot/actions/get-deal/get-deal.mjs
- components/hubspot/sources/new-ticket-property-change/new-ticket-property-change.mjs
- components/hubspot/actions/update-company/update-company.mjs
- components/hubspot/actions/list-marketing-emails/list-marketing-emails.mjs
- components/hubspot/actions/create-meeting/create-meeting.mjs
- components/hubspot/sources/new-custom-object-property-change/new-custom-object-property-change.mjs
⏰ 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). (4)
- GitHub Check: pnpm publish
- GitHub Check: Verify TypeScript components
- GitHub Check: Publish TypeScript components
- GitHub Check: Lint Code Base
🔇 Additional comments (3)
components/hubspot/actions/list-campaigns/list-campaigns.mjs (1)
7-7: Version bump looks goodNo functional change here; matches PR intent to rev the action version.
components/hubspot/sources/new-ticket/new-ticket.mjs (1)
12-12: LGTM: patch version bump only — new-ticket source invokes this.searchCRM, so it inherits the global 2 rps limiter (minTime: 500) and 429 retry/backoff logic.components/hubspot/actions/create-custom-object/create-custom-object.mjs (1)
9-9: Patch version bump OKLooks consistent with PR scope; no functional change here.
components/hubspot/actions/create-custom-object/create-custom-object.mjs
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @GTFalcao lgtm! Ready for QA!
|
Hi everyone, all test cases are passed! Ready for release! Test report |
The issue is the limit of 5 requests per second for the search endpoint specifically. We theoretically already enforce this per component, but each user can be running multiple components simultaneously (many HubSpot actions and sources need to use the search endpoint).
On top of reducing the max requests per second per component from 4 to 2, I'm implementing retrying up to 5 times on a 429 response (specifically for the search endpoint). I've added a bit of exponential backoff, but total delay between requests only goes up to 17 seconds to avoid component runs taking too long.
Summary by CodeRabbit
New Features
Chores