-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Freshservice extended implementation #17602
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
Freshservice extended implementation #17602
Conversation
- Add comprehensive app with all prop definitions and API methods - Add constants and utilities for consistent data handling - Add all 11 actions matching Freshdesk: * create-ticket, update-ticket (with internal notes support) * get-ticket, list-all-tickets * create-contact, create-company * assign-ticket-to-agent, assign-ticket-to-group * close-ticket, set-ticket-priority, set-ticket-status - Add internal notes support in update-ticket action - Enhance new-ticket source with proper date filtering - Add new-contact source - Update package.json with required dependencies - Full parity with Freshdesk integration functionality
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 1 Skipped Deployment
|
@seynadio is attempting to deploy a commit to the Pipedreamers Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughThis update introduces a comprehensive suite of Freshservice integration actions, utilities, and event sources. It includes new actions for ticket, company, and contact management, internal note handling, and ticket assignment. The Freshservice app is extended with property definitions, API methods, and constants. Event sources for new contacts and tickets are added or enhanced, and utility modules support data cleaning and pagination. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Action
participant FreshserviceApp
participant FreshserviceAPI
User->>Action: Provide input (e.g., create/update ticket)
Action->>FreshserviceApp: Call appropriate method (e.g., createTicket, updateTicket)
FreshserviceApp->>FreshserviceAPI: Send API request (with cleaned data)
FreshserviceAPI-->>FreshserviceApp: Return API response
FreshserviceApp-->>Action: Return result
Action-->>User: Export summary and result
sequenceDiagram
participant Source
participant FreshserviceApp
participant FreshserviceAPI
participant DB
Source->>DB: Get last checked date
Source->>FreshserviceApp: Fetch new contacts/tickets (paginated, filtered by date)
FreshserviceApp->>FreshserviceAPI: Request resource page
FreshserviceAPI-->>FreshserviceApp: Return resource page
FreshserviceApp-->>Source: Return resources
loop For each new resource
Source->>Source: Emit event
Source->>DB: Update max date if newer
end
Source->>DB: Store new last checked date
Suggested labels
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
components/freshdesk/actions/update-ticket/update-ticket.mjsOops! Something went wrong! :( ESLint: 8.57.1 Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'jsonc-eslint-parser' imported from /eslint.config.mjs components/freshservice/actions/close-ticket/close-ticket.mjsOops! Something went wrong! :( ESLint: 8.57.1 Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'jsonc-eslint-parser' imported from /eslint.config.mjs components/freshservice/actions/assign-ticket-to-agent/assign-ticket-to-agent.mjsOops! Something went wrong! :( ESLint: 8.57.1 Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'jsonc-eslint-parser' imported from /eslint.config.mjs
✨ Finishing Touches
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. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Thank you so much for submitting this! We've added it to our backlog to review, and our team has been notified. |
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: 5
🔭 Outside diff range comments (1)
components/freshservice/freshservice.app.mjs (1)
286-291
: Remove duplicate method definition.The
getTickets
method is a duplicate of thelistTickets
method defined at lines 245-250. They have identical implementations.- async getTickets(args = {}) { - return this._makeRequest({ - path: "/v2/tickets", - ...args, - }); - },
🧹 Nitpick comments (3)
components/freshservice/common/utils.mjs (1)
1-25
: LGTM: Solid utility function with minor suggestions.The
removeNullEntries
function correctly handles recursive cleaning of data structures. The implementation is clean and follows good practices.Consider these minor improvements:
function removeNullEntries(obj) { if (typeof obj === "number") { return obj; } if (typeof obj === "boolean") { return obj; } if (typeof obj === "string") { - return obj; + return obj.trim() === "" ? undefined : obj; } if (Array.isArray(obj)) { return obj.filter((item) => item !== null && item !== undefined && item !== "") .map((item) => removeNullEntries(item)); } if (typeof obj === "object" && obj !== null) { const result = {}; - for (const key in obj) { + for (const key of Object.keys(obj)) { if (obj[key] !== null && obj[key] !== undefined && obj[key] !== "") { result[key] = removeNullEntries(obj[key]); } } return result; } return obj; }This handles whitespace-only strings and avoids inherited properties in objects.
components/freshservice/actions/close-ticket/close-ticket.mjs (1)
22-22
: Consider using constants for status values.The hard-coded status value
5
for "Closed" should ideally reference a constant from the constants file to improve maintainability and readability.If constants are available in
components/freshservice/common/constants.mjs
, consider:- status: 5, // Closed + status: TICKET_STATUS.CLOSED, // or similar constantcomponents/freshservice/common/constants.mjs (1)
4-54
: Consider reducing duplication between object and array formats.The ticket status and priority mappings are duplicated in both object (TICKET_STATUS, TICKET_PRIORITY) and array (STATUS_OPTIONS, PRIORITY_OPTIONS) formats. While they serve different purposes, this duplication could lead to maintenance issues.
Consider generating the array options from the object mappings:
+const generateOptions = (mapping) => + Object.entries(mapping).map(([value, label]) => ({ + label, + value: parseInt(value), + })); -export const STATUS_OPTIONS = [ - { - label: "Open", - value: 2, - }, - { - label: "Pending", - value: 3, - }, - { - label: "Resolved", - value: 4, - }, - { - label: "Closed", - value: 5, - }, -]; +export const STATUS_OPTIONS = generateOptions(TICKET_STATUS); -export const PRIORITY_OPTIONS = [ - { - label: "Low", - value: 1, - }, - { - label: "Medium", - value: 2, - }, - { - label: "High", - value: 3, - }, - { - label: "Urgent", - value: 4, - }, -]; +export const PRIORITY_OPTIONS = generateOptions(TICKET_PRIORITY);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (18)
components/freshdesk/actions/update-ticket/update-ticket.mjs
(3 hunks)components/freshservice/actions/assign-ticket-to-agent/assign-ticket-to-agent.mjs
(1 hunks)components/freshservice/actions/assign-ticket-to-group/assign-ticket-to-group.mjs
(1 hunks)components/freshservice/actions/close-ticket/close-ticket.mjs
(1 hunks)components/freshservice/actions/create-company/create-company.mjs
(1 hunks)components/freshservice/actions/create-contact/create-contact.mjs
(1 hunks)components/freshservice/actions/create-ticket/create-ticket.mjs
(1 hunks)components/freshservice/actions/get-ticket/get-ticket.mjs
(1 hunks)components/freshservice/actions/list-all-tickets/list-all-tickets.mjs
(1 hunks)components/freshservice/actions/set-ticket-priority/set-ticket-priority.mjs
(1 hunks)components/freshservice/actions/set-ticket-status/set-ticket-status.mjs
(1 hunks)components/freshservice/actions/update-ticket/update-ticket.mjs
(1 hunks)components/freshservice/common/constants.mjs
(1 hunks)components/freshservice/common/utils.mjs
(1 hunks)components/freshservice/freshservice.app.mjs
(2 hunks)components/freshservice/package.json
(2 hunks)components/freshservice/sources/new-contact/new-contact.mjs
(1 hunks)components/freshservice/sources/new-ticket/new-ticket.mjs
(2 hunks)
🧰 Additional context used
🧠 Learnings (11)
components/freshservice/actions/list-all-tickets/list-all-tickets.mjs (2)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-07-04T18:11:59.822Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-10-08T15:33:38.240Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
components/freshservice/package.json (1)
Learnt from: jcortes
PR: PipedreamHQ/pipedream#14935
File: components/sailpoint/package.json:15-18
Timestamp: 2024-12-12T19:23:09.039Z
Learning: When developing Pipedream components, do not add built-in Node.js modules like `fs` to `package.json` dependencies, as they are native modules provided by the Node.js runtime.
components/freshservice/actions/create-company/create-company.mjs (3)
Learnt from: jcortes
PR: PipedreamHQ/pipedream#14467
File: components/gainsight_px/actions/create-account/create-account.mjs:4-6
Timestamp: 2024-10-30T15:24:39.294Z
Learning: In `components/gainsight_px/actions/create-account/create-account.mjs`, the action name should be "Create Account" instead of "Create Memory".
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-07-04T18:11:59.822Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-10-08T15:33:38.240Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
components/freshservice/actions/assign-ticket-to-agent/assign-ticket-to-agent.mjs (2)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-07-04T18:11:59.822Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-10-08T15:33:38.240Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
components/freshservice/sources/new-contact/new-contact.mjs (3)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#15376
File: components/monday/sources/name-updated/name-updated.mjs:6-6
Timestamp: 2025-01-23T03:55:15.166Z
Learning: Source names in Monday.com components don't need to start with "New" if they emit events for updated items (e.g., "Name Updated", "Column Value Updated") rather than new items. This follows the component guidelines exception where the "New" prefix is only required when emits are limited to new items.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#14265
File: components/the_magic_drip/sources/common.mjs:35-43
Timestamp: 2024-10-10T19:18:27.998Z
Learning: In `components/the_magic_drip/sources/common.mjs`, when processing items in `getAndProcessData`, `savedIds` is intentionally updated with IDs of both emitted and non-emitted items to avoid emitting retroactive events upon first deployment and ensure only new events are emitted as they occur.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12697
File: components/salesforce_rest_api/sources/common.mjs:97-98
Timestamp: 2024-07-24T02:05:59.531Z
Learning: The `processTimerEvent` method in the `components/salesforce_rest_api/sources/common.mjs` file is intentionally left unimplemented to enforce that subclasses must implement this method, similar to an abstract class in object-oriented programming.
components/freshservice/actions/update-ticket/update-ticket.mjs (1)
Learnt from: jcortes
PR: PipedreamHQ/pipedream#14467
File: components/gainsight_px/actions/create-account/create-account.mjs:4-6
Timestamp: 2024-10-30T15:24:39.294Z
Learning: In `components/gainsight_px/actions/create-account/create-account.mjs`, the action name should be "Create Account" instead of "Create Memory".
components/freshservice/actions/get-ticket/get-ticket.mjs (2)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-10-08T15:33:38.240Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-07-04T18:11:59.822Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
components/freshservice/actions/create-contact/create-contact.mjs (1)
Learnt from: jcortes
PR: PipedreamHQ/pipedream#14467
File: components/gainsight_px/actions/create-account/create-account.mjs:4-6
Timestamp: 2024-10-30T15:24:39.294Z
Learning: In `components/gainsight_px/actions/create-account/create-account.mjs`, the action name should be "Create Account" instead of "Create Memory".
components/freshservice/actions/create-ticket/create-ticket.mjs (3)
Learnt from: jcortes
PR: PipedreamHQ/pipedream#14467
File: components/gainsight_px/actions/create-account/create-account.mjs:4-6
Timestamp: 2024-10-30T15:24:39.294Z
Learning: In `components/gainsight_px/actions/create-account/create-account.mjs`, the action name should be "Create Account" instead of "Create Memory".
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-10-08T15:33:38.240Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#12731
File: components/hackerone/actions/get-members/get-members.mjs:3-28
Timestamp: 2024-07-04T18:11:59.822Z
Learning: When exporting a summary message in the `run` method of an action, ensure the message is correctly formatted. For example, in the `hackerone-get-members` action, the correct format is `Successfully retrieved ${response.data.length} members`.
components/freshservice/freshservice.app.mjs (1)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: In the Salesloft API integration (components/salesloft/salesloft.app.mjs), the _makeRequest method returns response.data which directly contains arrays for list endpoints like listPeople, listCadences, listUsers, and listAccounts. The propDefinitions correctly call .map() directly on these responses without needing to destructure a nested data property.
components/freshservice/sources/new-ticket/new-ticket.mjs (2)
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#14265
File: components/the_magic_drip/sources/common.mjs:35-43
Timestamp: 2024-10-10T19:18:27.998Z
Learning: In `components/the_magic_drip/sources/common.mjs`, when processing items in `getAndProcessData`, `savedIds` is intentionally updated with IDs of both emitted and non-emitted items to avoid emitting retroactive events upon first deployment and ensure only new events are emitted as they occur.
Learnt from: GTFalcao
PR: PipedreamHQ/pipedream#15376
File: components/monday/sources/name-updated/name-updated.mjs:6-6
Timestamp: 2025-01-23T03:55:15.166Z
Learning: Source names in Monday.com components don't need to start with "New" if they emit events for updated items (e.g., "Name Updated", "Column Value Updated") rather than new items. This follows the component guidelines exception where the "New" prefix is only required when emits are limited to new items.
🔇 Additional comments (20)
components/freshservice/package.json (2)
3-3
: LGTM: Version bump to 0.1.0 is appropriate.The version bump from 0.0.2 to 0.1.0 correctly reflects the addition of new features as described in the PR objectives.
17-17
: Verify compatibility with @pipedream/platform ^3.0.3.The major version upgrade from ^1.5.1 to ^3.0.3 could introduce breaking changes. Ensure all existing functionality remains compatible with the new platform version.
components/freshservice/actions/set-ticket-status/set-ticket-status.mjs (1)
4-39
: LGTM: Well-structured action following Pipedream conventions.The action implementation is clean and follows best practices:
- Proper use of property definitions from the main app
- Consistent error handling with the
$
parameter- User-friendly summary message with ticket name and human-readable status
- Appropriate return of the API response
components/freshservice/actions/set-ticket-priority/set-ticket-priority.mjs (1)
4-39
: LGTM: Consistent implementation following established patterns.The action implementation is well-structured and maintains consistency with the set-ticket-status action:
- Proper use of property definitions and constants
- Consistent error handling and user feedback
- Clean structure following Pipedream conventions
components/freshservice/actions/list-all-tickets/list-all-tickets.mjs (1)
3-55
: LGTM: Well-implemented list action with proper parameter handling.The action implementation is excellent:
- Optional parameters with sensible defaults and limits
- Conditional parameter construction to avoid unnecessary API parameters
- Proper fallback handling for the tickets array
- Summary message format follows established patterns from retrieved learnings
- Clean structure following Pipedream conventions
components/freshservice/actions/assign-ticket-to-group/assign-ticket-to-group.mjs (1)
1-37
: LGTM! Clean implementation of ticket assignment action.The action correctly implements ticket-to-group assignment using the Freshservice API. The code follows proper patterns with propDefinition references, appropriate API calls, and informative summary messages.
components/freshservice/actions/create-contact/create-contact.mjs (3)
92-94
: LGTM! Proper validation ensures required contact information.The validation correctly enforces that either email or phone must be provided, which aligns with typical contact creation requirements.
96-100
: LGTM! Clean data preparation with proper null handling.The implementation correctly uses
removeNullEntries
to clean the data and handles thesecondary_emails
array appropriately by checking for existence and length before adding it to the data object.
107-107
: LGTM! Safe property access in summary message.The summary message uses optional chaining to safely access nested properties, preventing potential runtime errors if the response structure differs.
components/freshservice/actions/assign-ticket-to-agent/assign-ticket-to-agent.mjs (2)
17-22
: LGTM! Proper property mapping for agent assignment.The mapping of
agentId
propDefinition toresponder_id
property is correct and follows the Freshservice API field naming convention.
24-36
: LGTM! Consistent implementation pattern.The action follows the same reliable pattern as other ticket assignment actions with proper API calls and informative summary messages.
components/freshservice/actions/create-company/create-company.mjs (3)
93-95
: LGTM! Proper custom fields handling.The conditional parsing of custom fields using
parseIfJSONString
is appropriate for handling JSON input while avoiding errors on non-JSON values.
97-99
: LGTM! Safe array handling for domains.The conditional check for domains existence and length prevents empty arrays from being sent to the API, which is good practice.
106-106
: LGTM! Safe property access in summary message.The summary message uses optional chaining to safely access the nested company name property, preventing potential runtime errors.
components/freshservice/actions/get-ticket/get-ticket.mjs (1)
1-27
: LGTM!Clean implementation following best practices. Good use of propDefinition for consistency and optional chaining for the summary message.
components/freshservice/actions/update-ticket/update-ticket.mjs (1)
111-163
: Well-implemented action with proper validationExcellent implementation that:
- Correctly validates required fields for both update paths
- Uses ConfigurationError for clear error messaging
- Properly excludes the app instance from API data
- Provides informative summaries with status/priority labels
components/freshservice/sources/new-ticket/new-ticket.mjs (1)
30-74
: Excellent refactor to use pagination and date filteringGreat improvements:
- Memory-efficient async generator pattern for pagination
- Date-based filtering to fetch only new tickets since last check
- Proper tracking of the maximum created date for incremental updates
- Clean implementation that scales well with large ticket volumes
components/freshservice/common/constants.mjs (1)
4-9
: Status code 1 is non-standard in Freshservice API v2
According to the Freshservice API v2 documentation, standard ticket status codes begin at 2 (“Open”) and run through 5 (“Closed”). There is no built-in code 1 to include inTICKET_STATUS
, so its omission is intentional and correct.components/freshservice/sources/new-contact/new-contact.mjs (2)
57-61
: Verify the query string format for the filter API.The query string has quotes around the entire query expression, which might not be the correct format for the Freshservice filter API.
- query: `"created_at:>'${formattedDate}'"`, + query: `created_at:>'${formattedDate}'`,Please verify the correct query format in the Freshservice API documentation. If the outer quotes are required, please disregard this suggestion.
23-29
: Handle potential null/undefined values in contact name.The summary string concatenation could display "null" or "undefined" if
last_name
is missing.- summary: `New contact: ${data.first_name} ${data.last_name || ""} (${data.email})`, + summary: `New contact: ${data.first_name}${data.last_name ? ` ${data.last_name}` : ""} (${data.email})`,⛔ Skipped due to learnings
Learnt from: GTFalcao PR: PipedreamHQ/pipedream#15376 File: components/monday/sources/name-updated/name-updated.mjs:6-6 Timestamp: 2025-01-23T03:55:15.166Z Learning: Source names in Monday.com components don't need to start with "New" if they emit events for updated items (e.g., "Name Updated", "Column Value Updated") rather than new items. This follows the component guidelines exception where the "New" prefix is only required when emits are limited to new items.
Learnt from: GTFalcao PR: PipedreamHQ/pipedream#14229 File: components/americommerce/actions/update-customer/update-customer.mjs:89-94 Timestamp: 2024-10-08T16:42:59.225Z Learning: When defining boolean properties in AmeriCommerce components (e.g., in `update-customer.mjs`), ensure that the label and description are consistent and clearly indicate the intent, especially when using negations like "No Account", to avoid confusion.
Learnt from: GTFalcao PR: PipedreamHQ/pipedream#14265 File: components/the_magic_drip/sources/common.mjs:35-43 Timestamp: 2024-10-10T19:18:27.998Z Learning: In `components/the_magic_drip/sources/common.mjs`, when processing items in `getAndProcessData`, `savedIds` is intentionally updated with IDs of both emitted and non-emitted items to avoid emitting retroactive events upon first deployment and ensure only new events are emitted as they occur.
"async-retry": "^1.3.3", | ||
"moment": "2.29.4" |
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.
💡 Verification agent
🧩 Analysis chain
Verify security status of the fixed moment version.
The fixed version of moment (2.29.4) may have known security vulnerabilities or be outdated. Consider updating to the latest stable version.
🌐 Web query:
What are the known security vulnerabilities in moment.js version 2.29.4 and what is the latest stable version?
💡 Result:
moment.js version 2.29.4 is not known to have any active or recent security vulnerabilities. The major security issue previously reported—a Regular Expression Denial of Service (ReDoS) vulnerability in the RFC2822 parsing code—was patched in 2.29.4; earlier versions (from 2.18.0 up to 2.29.3) were affected by this vulnerability (CVE-2022-31129)[1][2][4]. Cybersecurity vulnerability trackers do not report any unresolved issues for 2.29.4[9].
Key points:
- 2.29.4 fixes previous ReDoS issue: The ReDoS vulnerability, which affected string-to-date parsing (especially RFC2822 parsing), was patched in 2.29.4. This resolved the main known security risk up to that release[2][4].
- No new vulnerabilities reported in 2.29.4: Security databases and advisories currently list no recent or active vulnerabilities for this version[9].
- Input validation still recommended: Even with the patch, developers are advised to limit the length of user-supplied date strings to further mitigate any potential for resource exhaustion[4].
The latest stable version of moment.js is 2.30.1 (released December 27, 2023)[2][10].
A summary table:
Version | Known Security Vulnerabilities | Notes |
---|---|---|
2.29.4 | None currently known; fixed previous ReDoS | ReDoS fixed from <2.29.4 |
2.30.1 | None reported | Latest stable release |
If you need maximum security and the latest patches—even though 2.29.4 is safe regarding known issues—upgrading to 2.30.1 is recommended[2][10].
Citations:
- 1: https://forum.camunda.io/t/moment-js-vulnerability-for-version-2-29-4/39554
- 2: https://github.com/moment/moment/blob/develop/CHANGELOG.md
- 3: https://vulert.com/vuln-db/CVE-2017-18214
- 4: Moment.js 2.29.4 CVE-2022-31129 primefaces/primefaces#8968
- 5: https://momentjs.com/docs/
- 6: https://vulert.com/vuln-db/CVE-2016-4055
- 7: https://forum.opensearch.org/t/moment-js-vulnerabilities-question/11858
- 8: https://github.com/moment/moment-timezone/releases
- 9: https://www.cybersecurity-help.cz/vdb/moment_project/moment/2.29.4/
- 10: https://momentjs.com
Confirm moment.js 2.29.4 Security Status & Recommend Upgrade
moment.js 2.29.4 patches the known ReDoS vulnerability (CVE-2022-31129) and currently has no active security issues. The latest stable release is 2.30.1 (Dec 27, 2023). To stay up-to-date with any future fixes and improvements, consider upgrading.
• File: components/freshservice/package.json
Lines: 18–19
Suggested diff:
- "moment": "2.29.4"
+ "moment": "^2.30.1"
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"async-retry": "^1.3.3", | |
"moment": "2.29.4" | |
"async-retry": "^1.3.3", | |
"moment": "^2.30.1" |
🤖 Prompt for AI Agents
In components/freshservice/package.json at lines 18 to 19, the moment.js version
is set to 2.29.4. To ensure the package stays current with the latest fixes and
improvements, update the moment.js dependency version from "2.29.4" to "2.30.1".
if (internalNote && noteBody) { | ||
const response = await freshdesk._makeRequest({ | ||
$, | ||
method: "POST", | ||
url: `/tickets/${ticketId}/notes`, | ||
data: { | ||
body: noteBody, | ||
private: true, | ||
}, | ||
}); | ||
|
||
$.export("$summary", `Internal note added to ticket "${ticketName}" (ID: ${ticketId})`); | ||
return response; | ||
} |
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.
Add validation for required noteBody when internalNote is enabled
When internalNote
is true but noteBody
is empty or not provided, the code silently falls through to the ticket update logic. This could confuse users who expect to add a note.
Consider adding validation similar to the Freshservice implementation:
if (internalNote && noteBody) {
+if (internalNote) {
+ if (!noteBody) {
+ throw new Error("Note Body is required when Internal Note is enabled");
+ }
const response = await freshdesk._makeRequest({
$,
method: "POST",
url: `/tickets/${ticketId}/notes`,
data: {
body: noteBody,
private: true,
},
});
$.export("$summary", `Internal note added to ticket "${ticketName}" (ID: ${ticketId})`);
return response;
}
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In components/freshdesk/actions/update-ticket/update-ticket.mjs around lines 120
to 133, add validation to check if noteBody is provided when internalNote is
true. If noteBody is missing or empty, throw an error or return a clear message
indicating that the note body is required before proceeding. This prevents
silent failures and ensures users are informed when they attempt to add an
internal note without content.
async run({ $ }) { | ||
const { | ||
custom_fields, | ||
...otherProps | ||
} = this; | ||
|
||
const data = removeNullEntries(otherProps); | ||
|
||
if (custom_fields) { | ||
data.custom_fields = this.freshservice.parseIfJSONString(custom_fields); | ||
} |
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.
Fix destructuring to exclude freshservice from API data
The current destructuring only extracts custom_fields
, leaving the freshservice
app instance in otherProps
. This will incorrectly pass the app instance to the API.
Apply this fix:
async run({ $ }) {
const {
+ freshservice,
custom_fields,
...otherProps
} = this;
const data = removeNullEntries(otherProps);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
async run({ $ }) { | |
const { | |
custom_fields, | |
...otherProps | |
} = this; | |
const data = removeNullEntries(otherProps); | |
if (custom_fields) { | |
data.custom_fields = this.freshservice.parseIfJSONString(custom_fields); | |
} | |
async run({ $ }) { | |
const { | |
freshservice, | |
custom_fields, | |
...otherProps | |
} = this; | |
const data = removeNullEntries(otherProps); | |
if (custom_fields) { | |
data.custom_fields = this.freshservice.parseIfJSONString(custom_fields); | |
} |
🤖 Prompt for AI Agents
In components/freshservice/actions/create-ticket/create-ticket.mjs around lines
122 to 132, the destructuring only excludes custom_fields but leaves the
freshservice app instance in otherProps, causing it to be sent to the API
incorrectly. Update the destructuring to also exclude freshservice from this by
adding it to the destructuring assignment, so neither custom_fields nor
freshservice are included in otherProps before calling removeNullEntries.
async *getContacts(params = {}) { | ||
let page = 1; | ||
let hasMore = true; | ||
|
||
while (hasMore) { | ||
const { requesters } = await this.freshservice.filterContacts({ | ||
params: { | ||
...params, | ||
page, | ||
per_page: 100, | ||
}, | ||
}); |
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.
🛠️ Refactor suggestion
Use PAGE_SIZE constant for consistency.
The method uses a hardcoded value of 100 for pagination instead of the PAGE_SIZE constant defined in constants.mjs.
Import the constant at the top of the file:
+import { PAGE_SIZE } from "../../common/constants.mjs";
Then update the pagination parameter:
- per_page: 100,
+ per_page: PAGE_SIZE,
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
async *getContacts(params = {}) { | |
let page = 1; | |
let hasMore = true; | |
while (hasMore) { | |
const { requesters } = await this.freshservice.filterContacts({ | |
params: { | |
...params, | |
page, | |
per_page: 100, | |
}, | |
}); | |
import { PAGE_SIZE } from "../../common/constants.mjs"; | |
async *getContacts(params = {}) { | |
let page = 1; | |
let hasMore = true; | |
while (hasMore) { | |
const { requesters } = await this.freshservice.filterContacts({ | |
params: { | |
...params, | |
page, | |
per_page: PAGE_SIZE, | |
}, | |
}); |
🤖 Prompt for AI Agents
In components/freshservice/sources/new-contact/new-contact.mjs around lines 30
to 41, replace the hardcoded pagination value 100 with the PAGE_SIZE constant
for consistency. First, import PAGE_SIZE from constants.mjs at the top of the
file, then update the per_page parameter in the filterContacts call to use
PAGE_SIZE instead of 100.
async options({ | ||
page, companyId, | ||
}) { | ||
const contacts = await this.getContacts({ | ||
params: { | ||
page: page + 1, | ||
per_page: PAGE_SIZE, | ||
company_id: companyId, | ||
}, | ||
}); | ||
return contacts?.map((contact) => ({ | ||
label: contact.email, | ||
value: contact.email, | ||
})) || []; | ||
}, |
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.
💡 Verification agent
🧩 Analysis chain
Verify the API response structure for contacts.
The getContacts
method response is accessed directly without checking for a wrapper property. Based on other methods in this file, the API might return contacts in a wrapped format.
🏁 Script executed:
#!/bin/bash
# Description: Check how getContacts response is structured in other usages
# Search for other usages of getContacts to understand the response structure
ast-grep --pattern 'getContacts($_) {
$$$
}'
# Also search for how the response is handled
rg -A 5 'getContacts\(' --type js
Length of output: 84
🏁 Script executed:
#!/bin/bash
# Search for the getContacts method definition and its implementation in the codebase
# 1. Find all occurrences of getContacts across the repo
rg -n "getContacts" .
# 2. Inspect the implementation in components/freshservice/freshservice.app.mjs (if found)
rg -A5 "async getContacts" components/freshservice/freshservice.app.mjs
Length of output: 13294
🏁 Script executed:
#!/bin/bash
# Inspect getTickets implementation and usage in freshservice.app.mjs
rg -n "async getTickets" -A10 components/freshservice/freshservice.app.mjs
# Inspect the _makeRequest method definition in freshservice.app.mjs
rg -n "_makeRequest" -A10 components/freshservice/freshservice.app.mjs
Length of output: 3663
🏁 Script executed:
#!/bin/bash
# Display the top 20 lines of freshservice.app.mjs to inspect imports and axios usage
head -n 20 components/freshservice/freshservice.app.mjs
Length of output: 561
🏁 Script executed:
#!/bin/bash
# Search for contactEmail in propDefinitions
rg -n "contactEmail" -A5 components/freshservice/freshservice.app.mjs
Length of output: 251
The getContacts
call returns the raw Axios response object (with a top-level data
property), not the array of contacts itself. Your current options
handler tries to call .map()
on this response object, so it will fail at runtime.
To fix this, extract the array of contacts from response.data
. For example:
async options({ page, companyId }) {
const response = await this.getContacts({
params: {
page: page + 1,
per_page: PAGE_SIZE,
company_id: companyId,
},
});
const contacts = response.data?.requesters || [];
return contacts.map(contact => ({
label: contact.email,
value: contact.email,
}));
},
• The Freshservice API returns requesters under response.data.requesters
.
• Update line 103 in components/freshservice/freshservice.app.mjs
.
• Remove the duplicate getTickets
at lines 286–291; the existing listTickets
covers this.
🤖 Prompt for AI Agents
In components/freshservice/freshservice.app.mjs around lines 100 to 114, the
options method incorrectly calls .map() on the raw Axios response object
returned by getContacts instead of the contacts array. Fix this by extracting
the contacts array from response.data.requesters before mapping. Also, remove
the duplicate getTickets method found at lines 286 to 291 since listTickets
already covers that functionality.
Closing this PR and replacing with #17608 which has only the Freshservice changes (no accidental Freshdesk changes) and represents a complete, comprehensive integration with full parity to Freshdesk functionality |
WHY
Summary by CodeRabbit
New Features
Improvements
Chores