-
Notifications
You must be signed in to change notification settings - Fork 5.6k
[ACTIONS] Netsuite - new components #19363
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
base: master
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
WalkthroughAdds a full NetSuite integration: app-level REST client and CRUD helpers for invoices and sales orders, ten new action modules (create/get/list/update/delete), utilities for safe JSON parsing, validation constants, pagination support, and expanded propDefinitions for dynamic UI selection. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (2 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
80e4f15 to
a4e6ce2
Compare
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: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
components/netsuite/package.json (1)
3-15: Add trailing newline to fix eslint eol-last failureVersion bump to
0.1.0looks appropriate, and the minimal manifest avoids unnecessary dependencies (consistent with not adding Node built-ins as deps, based on learnings). The remaining issue is the eslint error about a missing newline at end of file.Add a trailing newline after the closing brace to satisfy
eol-lastand unblock the checks:- } -} + } +} +
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (14)
components/netsuite/actions/create-invoice/create-invoice.mjs(1 hunks)components/netsuite/actions/create-sales-order/create-sales-order.mjs(1 hunks)components/netsuite/actions/delete-invoice/delete-invoice.mjs(1 hunks)components/netsuite/actions/delete-sales-order/delete-sales-order.mjs(1 hunks)components/netsuite/actions/get-invoice/get-invoice.mjs(1 hunks)components/netsuite/actions/get-sales-order/get-sales-order.mjs(1 hunks)components/netsuite/actions/list-invoices/list-invoices.mjs(1 hunks)components/netsuite/actions/list-sales-orders/list-sales-orders.mjs(1 hunks)components/netsuite/actions/update-invoice/update-invoice.mjs(1 hunks)components/netsuite/actions/update-sales-order/update-sales-order.mjs(1 hunks)components/netsuite/common/constants.mjs(1 hunks)components/netsuite/common/utils.mjs(1 hunks)components/netsuite/netsuite.app.mjs(1 hunks)components/netsuite/package.json(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2024-10-30T15:24:39.294Z
Learnt from: jcortes
Repo: PipedreamHQ/pipedream PR: 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".
Applied to files:
components/netsuite/actions/create-sales-order/create-sales-order.mjs
📚 Learning: 2025-06-04T17:52:05.780Z
Learnt from: GTFalcao
Repo: PipedreamHQ/pipedream PR: 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.
Applied to files:
components/netsuite/netsuite.app.mjs
📚 Learning: 2025-06-04T17:52:05.780Z
Learnt from: GTFalcao
Repo: PipedreamHQ/pipedream PR: 16954
File: components/salesloft/salesloft.app.mjs:14-23
Timestamp: 2025-06-04T17:52:05.780Z
Learning: The Salesloft API list endpoints (listPeople, listCadences, listUsers, listAccounts) return arrays directly in the response body, not wrapped in a metadata object with a nested data property. The _makeRequest method correctly returns response.data which contains the arrays that can be mapped over directly in propDefinitions.
Applied to files:
components/netsuite/netsuite.app.mjs
📚 Learning: 2024-12-12T19:23:09.039Z
Learnt from: jcortes
Repo: PipedreamHQ/pipedream PR: 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.
Applied to files:
components/netsuite/package.json
🧬 Code graph analysis (5)
components/netsuite/actions/list-sales-orders/list-sales-orders.mjs (2)
components/netsuite/actions/list-invoices/list-invoices.mjs (2)
items(40-40)paginator(41-50)components/netsuite/netsuite.app.mjs (1)
items(303-303)
components/netsuite/actions/get-invoice/get-invoice.mjs (8)
components/netsuite/actions/create-invoice/create-invoice.mjs (1)
response(119-147)components/netsuite/actions/create-sales-order/create-sales-order.mjs (1)
response(95-123)components/netsuite/actions/delete-invoice/delete-invoice.mjs (1)
response(30-33)components/netsuite/actions/delete-sales-order/delete-sales-order.mjs (1)
response(30-33)components/netsuite/actions/get-sales-order/get-sales-order.mjs (1)
response(51-59)components/netsuite/actions/update-invoice/update-invoice.mjs (1)
response(135-167)components/netsuite/actions/update-sales-order/update-sales-order.mjs (1)
response(110-142)components/netsuite/netsuite.app.mjs (1)
response(294-301)
components/netsuite/actions/update-sales-order/update-sales-order.mjs (3)
components/netsuite/actions/create-sales-order/create-sales-order.mjs (1)
response(95-123)components/netsuite/actions/update-invoice/update-invoice.mjs (1)
response(135-167)components/netsuite/netsuite.app.mjs (2)
response(294-301)items(303-303)
components/netsuite/actions/delete-sales-order/delete-sales-order.mjs (1)
components/netsuite/actions/delete-invoice/delete-invoice.mjs (1)
response(30-33)
components/netsuite/actions/create-invoice/create-invoice.mjs (4)
components/netsuite/actions/create-sales-order/create-sales-order.mjs (1)
response(95-123)components/netsuite/actions/update-invoice/update-invoice.mjs (1)
response(135-167)components/netsuite/actions/update-sales-order/update-sales-order.mjs (1)
response(110-142)components/netsuite/netsuite.app.mjs (2)
response(294-301)items(303-303)
🪛 GitHub Actions: Pull Request Checks
components/netsuite/package.json
[error] 15-15: eslint: Newline required at end of file but not found. (eol-last) during 'pnpm exec eslint ...'
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: pnpm publish
🔇 Additional comments (8)
components/netsuite/common/constants.mjs (1)
1-7: Validation constants look goodThe
VALIDATION_OPTIONSmap is clear and aligns well with how the actions configure validation behavior. No changes needed here.components/netsuite/actions/delete-sales-order/delete-sales-order.mjs (1)
1-37: Delete Sales Order action is consistent and straightforwardThe action wiring (props, annotations, and
runimplementation) is consistent with the existing delete-invoice pattern and correctly delegates toapp.deleteSalesOrder, emitting a clear summary.No issues from a correctness or API-shape standpoint.
components/netsuite/actions/get-invoice/get-invoice.mjs (1)
1-64: Get Invoice action matches established patternProps, annotations, and the
rundelegation toapp.getInvoice(including optional params and summary) are consistent with the corresponding get-sales-order action and look correct.No changes needed here.
components/netsuite/actions/update-invoice/update-invoice.mjs (1)
1-172: Update Invoice action wiring and payload construction look correctThe props schema, validation headers, query params (
replace,replaceSelectedFields), and conditional assembly of thedatapayload (entity, subsidiary, items, memo, otherRefNum, additionalFields) are all consistent with the related create/update actions and NetSuite expectations.The only caveat is that this action relies on
utils.parseJsonforitemsandadditionalFields; once the depth/cycle handling in that utility is corrected (see comment incomponents/netsuite/common/utils.mjs), this action should behave as intended.components/netsuite/actions/create-sales-order/create-sales-order.mjs (1)
1-128: Create Sales Order action is well-structured and consistentThe action metadata, prop definitions, and
runimplementation align with the create-invoice pattern and correctly delegate toapp.createSalesOrderwith validation headers and a properly assembled payload (including parseditemsandadditionalFields).The name "Create Sales Order" correctly reflects the behavior, which is good alignment with prior feedback on action naming. Aside from the shared
parseJsonutility concerns already noted, this action looks solid.components/netsuite/actions/list-invoices/list-invoices.mjs (1)
1-61: List Invoices action correctly leverages pagination helperThe action uses
app.paginatein the same way as the list-sales-orders action, with appropriate conditional search params and a clear summary message. Thefor awaitaccumulation intoitemsand return value are straightforward and correct.No changes needed here.
components/netsuite/actions/create-invoice/create-invoice.mjs (1)
104-147: Create‑invoice action wiring looks correct and consistentThe
createInvoicecall uses the same flattened options shape ascreateSalesOrder/updateInvoice, so$, validation headers,replace, and the payload (including parseditemsandadditionalFields) will be forwarded correctly to_makeRequest. This action is structurally sound once the shared app helpers are fixed.components/netsuite/actions/update-sales-order/update-sales-order.mjs (1)
110-141: The review comment identifies a critical issue regarding argument handling in theupdateSalesOrdercall, but this cannot be verified without access to thenetsuite.app.mjsimplementation. The claim that headers, params, and data are being ignored requires examining the actual function signature and how it processes theoptsparameter. Manual code inspection of the app file is necessary to confirm whether the suggested nestedoptsstructure or an app-level fix is required.
| async run({ $ }) { | ||
| const { | ||
| app, | ||
| invoiceId, | ||
| } = this; | ||
|
|
||
| const response = await app.deleteInvoice({ | ||
| $, | ||
| invoiceId, | ||
| }); |
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.
🧩 Analysis chain
🏁 Script executed:
find . -type f -name "netsuite.app.mjs" | head -5Repository: PipedreamHQ/pipedream
Length of output: 103
🏁 Script executed:
cat -n ./components/netsuite/netsuite.app.mjs | head -150Repository: PipedreamHQ/pipedream
Length of output: 5400
🏁 Script executed:
rg -n "deleteInvoice|_makeRequest" ./components/netsuite/netsuite.app.mjs | head -30Repository: PipedreamHQ/pipedream
Length of output: 561
🏁 Script executed:
sed -n '187,195p' ./components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 268
🏁 Script executed:
sed -n '265,273p' ./components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 253
🏁 Script executed:
sed -n '197,210p' ./components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 366
🏁 Script executed:
rg -n "createInvoice|updateInvoice" ./components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 123
🏁 Script executed:
sed -n '249,273p' ./components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 589
🏁 Script executed:
cat -n ./components/netsuite/actions/delete-invoice/delete-invoice.mjsRepository: PipedreamHQ/pipedream
Length of output: 1179
🏁 Script executed:
cat -n ./components/netsuite/actions/create-invoice/create-invoice.mjs | head -50Repository: PipedreamHQ/pipedream
Length of output: 1941
🏁 Script executed:
sed -n '60,90p' ./components/netsuite/actions/create-invoice/create-invoice.mjsRepository: PipedreamHQ/pipedream
Length of output: 935
🏁 Script executed:
sed -n '85,130p' ./components/netsuite/actions/create-invoice/create-invoice.mjsRepository: PipedreamHQ/pipedream
Length of output: 971
🏁 Script executed:
sed -n '20,60p' ./components/netsuite/actions/update-invoice/update-invoice.mjsRepository: PipedreamHQ/pipedream
Length of output: 1118
🏁 Script executed:
grep -n "async run" ./components/netsuite/actions/update-invoice/update-invoice.mjsRepository: PipedreamHQ/pipedream
Length of output: 89
🏁 Script executed:
sed -n '118,155p' ./components/netsuite/actions/update-invoice/update-invoice.mjsRepository: PipedreamHQ/pipedream
Length of output: 896
🏁 Script executed:
rg -A 3 "async run\(\{ \$ \}\)" ./components/netsuite/actions/*/update-invoice/update-invoice.mjs | head -20Repository: PipedreamHQ/pipedream
Length of output: 170
$ is ignored by deleteInvoice with current app signature
deleteInvoice is declared as ({ invoiceId, opts } = {}), so passing { $, invoiceId } here sets only invoiceId; $ is dropped and _makeRequest falls back to $ = this. The DELETE request will still execute, but step context and logging are lost. To fix, nest $ under opts:
const response = await app.deleteInvoice({
- $,
invoiceId,
+ opts: {
+ $,
+ },
});Alternatively, update deleteInvoice in netsuite.app.mjs to accept top-level options like createInvoice does (signature: createInvoice(opts = {})), which would provide consistency across all invoice methods.
📝 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 { | |
| app, | |
| invoiceId, | |
| } = this; | |
| const response = await app.deleteInvoice({ | |
| $, | |
| invoiceId, | |
| }); | |
| async run({ $ }) { | |
| const { | |
| app, | |
| invoiceId, | |
| } = this; | |
| const response = await app.deleteInvoice({ | |
| invoiceId, | |
| opts: { | |
| $, | |
| }, | |
| }); |
🤖 Prompt for AI Agents
In components/netsuite/actions/delete-invoice/delete-invoice.mjs around lines 24
to 33, the call to app.deleteInvoice currently passes $ at the top-level which
is ignored because deleteInvoice signature is ({ invoiceId, opts } = {}); update
the call to pass the step context inside opts (i.e., call deleteInvoice with
invoiceId and opts: { $ }) so _makeRequest receives the step context and logging
remains intact; alternatively, modify netsuite.app.mjs to change deleteInvoice
to accept a single opts object similar to createInvoice (signature like
deleteInvoice(opts = {})) so top-level options including $ are honored
consistently across invoice methods.
| const response = await app.getSalesOrder({ | ||
| $, | ||
| salesOrderId, | ||
| params: { | ||
| expandSubResources, | ||
| simpleEnumFormat, | ||
| 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.
🧩 Analysis chain
🏁 Script executed:
# First, find the netsuite app file
find . -name "netsuite.app.mjs" -o -name "*netsuite*app*" | head -20Repository: PipedreamHQ/pipedream
Length of output: 186
🏁 Script executed:
# Also locate the file mentioned in the review
find . -path "*netsuite/actions/get-sales-order*" -type fRepository: PipedreamHQ/pipedream
Length of output: 130
🏁 Script executed:
# Find the netsuite app definition file
find . -path "*netsuite*" -name "*.mjs" | grep -i app | head -10Repository: PipedreamHQ/pipedream
Length of output: 103
🏁 Script executed:
# Read the get-sales-order action file to see the full context
head -70 ./components/netsuite/actions/get-sales-order/get-sales-order.mjsRepository: PipedreamHQ/pipedream
Length of output: 1398
🏁 Script executed:
# Read the netsuite app file to see getSalesOrder implementation
cat ./components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 8324
getSalesOrder call is dropping $ and query params with current app signature
getSalesOrder destructures only salesOrderId and opts from its argument object, so the top-level $ and params keys you're passing are ignored. This means expandSubResources, simpleEnumFormat, and fields never reach the API, and _makeRequest falls back to $ = this instead of using the step context. Nest these under opts:
- const response = await app.getSalesOrder({
- $,
- salesOrderId,
- params: {
- expandSubResources,
- simpleEnumFormat,
- fields,
- },
- });
+ const response = await app.getSalesOrder({
+ salesOrderId,
+ opts: {
+ $,
+ params: {
+ expandSubResources,
+ simpleEnumFormat,
+ fields,
+ },
+ },
+ });📝 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.
| const response = await app.getSalesOrder({ | |
| $, | |
| salesOrderId, | |
| params: { | |
| expandSubResources, | |
| simpleEnumFormat, | |
| fields, | |
| }, | |
| }); | |
| const response = await app.getSalesOrder({ | |
| salesOrderId, | |
| opts: { | |
| $, | |
| params: { | |
| expandSubResources, | |
| simpleEnumFormat, | |
| fields, | |
| }, | |
| }, | |
| }); |
🤖 Prompt for AI Agents
components/netsuite/actions/get-sales-order/get-sales-order.mjs around lines 51
to 59: the current call passes $ and params at the top level but getSalesOrder
only destructures salesOrderId and opts, so those values are ignored; fix by
moving $ and your query params (expandSubResources, simpleEnumFormat, fields)
into the opts property so the call supplies salesOrderId and opts:{ $: <step
context>, params: { expandSubResources, simpleEnumFormat, fields } } ensuring
the step context ($) and query options reach the API.
| const items = []; | ||
| const paginator = app.paginate({ | ||
| fn: app.listSalesOrders, | ||
| fnArgs: { | ||
| $, | ||
| params: { | ||
| q: searchQuery, | ||
| }, | ||
| }, | ||
| maxResults, | ||
| }); |
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.
🧩 Analysis chain
🏁 Script executed:
fd -t f "netsuite.app.mjs" --type fRepository: PipedreamHQ/pipedream
Length of output: 186
🏁 Script executed:
fd -t f "\.mjs$" | grep -E "(netsuite|app)" | head -20Repository: PipedreamHQ/pipedream
Length of output: 186
🏁 Script executed:
git ls-files | grep -E "netsuite.*app"Repository: PipedreamHQ/pipedream
Length of output: 101
🏁 Script executed:
cat -n components/netsuite/netsuite.app.mjs | head -200Repository: PipedreamHQ/pipedream
Length of output: 7245
🏁 Script executed:
wc -l components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 105
🏁 Script executed:
cat -n components/netsuite/actions/list-sales-orders/list-sales-orders.mjsRepository: PipedreamHQ/pipedream
Length of output: 1763
🏁 Script executed:
grep -n "paginate" components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 90
🏁 Script executed:
sed -n '200,322p' components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 2553
🏁 Script executed:
sed -n '175,195p' components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 644
Unbound fn breaks listSalesOrders inside paginate
The paginate method calls fn({...}) at line 299 without binding context. When fn is app.listSalesOrders, the method loses its this binding, causing this._makeRequest to fail with an undefined reference error.
Fix by binding the method:
- const paginator = app.paginate({
- fn: app.listSalesOrders,
+ const paginator = app.paginate({
+ fn: app.listSalesOrders.bind(app),Alternatively, update paginate in netsuite.app.mjs (line 299) to preserve context:
- const response = await fn({
+ const response = await fn.call(this, {🤖 Prompt for AI Agents
In components/netsuite/actions/list-sales-orders/list-sales-orders.mjs around
lines 37 to 47, the code passes app.listSalesOrders into paginate unbound which
causes loss of `this` (breaking this._makeRequest inside listSalesOrders); fix
by passing a bound function or wrapper so the method retains its app context
(for example, set fn to app.listSalesOrders.bind(app) or to a small arrow
wrapper that calls app.listSalesOrders(...)); alternatively, update paginate in
netsuite.app.mjs to call the passed function with the app as its receiver (e.g.
fn.call(app, ...)) so the original method context is preserved.
| const parseJson = (input, maxDepth = 100) => { | ||
| const seen = new WeakSet(); | ||
| const parse = (value) => { | ||
| if (maxDepth <= 0) { | ||
| return value; | ||
| } | ||
| if (typeof(value) === "string") { | ||
| // Only parse if the string looks like a JSON object or array | ||
| const trimmed = value.trim(); | ||
| if ( | ||
| (trimmed.startsWith("{") && trimmed.endsWith("}")) || | ||
| (trimmed.startsWith("[") && trimmed.endsWith("]")) | ||
| ) { | ||
| try { | ||
| return parseJson(JSON.parse(value), maxDepth - 1); | ||
| } catch (e) { | ||
| return value; | ||
| } | ||
| } | ||
| return value; | ||
| } else if (typeof(value) === "object" && value !== null && !Array.isArray(value)) { | ||
| if (seen.has(value)) { | ||
| return value; | ||
| } | ||
| seen.add(value); | ||
| return Object.entries(value) | ||
| .reduce((acc, [ | ||
| key, | ||
| val, | ||
| ]) => Object.assign(acc, { | ||
| [key]: parse(val), | ||
| }), {}); | ||
| } else if (Array.isArray(value)) { | ||
| return value.map((item) => parse(item)); | ||
| } | ||
| return value; | ||
| }; | ||
|
|
||
| return parse(input); | ||
| }; | ||
|
|
||
| export default { | ||
| parseJson, | ||
| }; |
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 depth handling and circular array detection in parseJson
The current implementation has two important pitfalls:
maxDepthis effectively not enforced for nested objects/arrays:parsecloses overmaxDepthbut never updates it, soif (maxDepth <= 0)never changes as recursion proceeds (except when re-entering viaparseJsonon strings).- Arrays are not tracked in
seen, so a self-referential array (or cycles involving arrays) can cause infinite recursion / stack overflow.
You can address both by:
- Passing a
depthargument through recursive calls and checkingdepth >= maxDepth. - Treating any non-null object (including arrays) as candidates for cycle detection in the
WeakSet. - Reusing
parseafterJSON.parseinstead of re-enteringparseJson, so a singleseenset and depth counter are used consistently.
Example refactor:
-const parseJson = (input, maxDepth = 100) => {
- const seen = new WeakSet();
- const parse = (value) => {
- if (maxDepth <= 0) {
- return value;
- }
- if (typeof(value) === "string") {
- // Only parse if the string looks like a JSON object or array
- const trimmed = value.trim();
- if (
- (trimmed.startsWith("{") && trimmed.endsWith("}")) ||
- (trimmed.startsWith("[") && trimmed.endsWith("]"))
- ) {
- try {
- return parseJson(JSON.parse(value), maxDepth - 1);
- } catch (e) {
- return value;
- }
- }
- return value;
- } else if (typeof(value) === "object" && value !== null && !Array.isArray(value)) {
- if (seen.has(value)) {
- return value;
- }
- seen.add(value);
- return Object.entries(value)
- .reduce((acc, [
- key,
- val,
- ]) => Object.assign(acc, {
- [key]: parse(val),
- }), {});
- } else if (Array.isArray(value)) {
- return value.map((item) => parse(item));
- }
- return value;
- };
-
- return parse(input);
-};
+const parseJson = (input, maxDepth = 100) => {
+ const seen = new WeakSet();
+
+ const parse = (value, depth = 0) => {
+ if (depth >= maxDepth) {
+ return value;
+ }
+
+ if (typeof value === "string") {
+ // Only parse if the string looks like a JSON object or array
+ const trimmed = value.trim();
+ if (
+ (trimmed.startsWith("{") && trimmed.endsWith("}")) ||
+ (trimmed.startsWith("[") && trimmed.endsWith("]"))
+ ) {
+ try {
+ return parse(JSON.parse(value), depth + 1);
+ } catch (e) {
+ return value;
+ }
+ }
+ return value;
+ }
+
+ if (value && typeof value === "object") {
+ if (seen.has(value)) {
+ return value;
+ }
+ seen.add(value);
+
+ if (Array.isArray(value)) {
+ return value.map((item) => parse(item, depth + 1));
+ }
+
+ return Object.fromEntries(
+ Object.entries(value)
+ .map(([key, val]) => [key, parse(val, depth + 1)]),
+ );
+ }
+
+ return value;
+ };
+
+ return parse(input);
+};This preserves the external API while making maxDepth meaningful and preventing cycles (including arrays) from blowing the stack.
📝 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.
| const parseJson = (input, maxDepth = 100) => { | |
| const seen = new WeakSet(); | |
| const parse = (value) => { | |
| if (maxDepth <= 0) { | |
| return value; | |
| } | |
| if (typeof(value) === "string") { | |
| // Only parse if the string looks like a JSON object or array | |
| const trimmed = value.trim(); | |
| if ( | |
| (trimmed.startsWith("{") && trimmed.endsWith("}")) || | |
| (trimmed.startsWith("[") && trimmed.endsWith("]")) | |
| ) { | |
| try { | |
| return parseJson(JSON.parse(value), maxDepth - 1); | |
| } catch (e) { | |
| return value; | |
| } | |
| } | |
| return value; | |
| } else if (typeof(value) === "object" && value !== null && !Array.isArray(value)) { | |
| if (seen.has(value)) { | |
| return value; | |
| } | |
| seen.add(value); | |
| return Object.entries(value) | |
| .reduce((acc, [ | |
| key, | |
| val, | |
| ]) => Object.assign(acc, { | |
| [key]: parse(val), | |
| }), {}); | |
| } else if (Array.isArray(value)) { | |
| return value.map((item) => parse(item)); | |
| } | |
| return value; | |
| }; | |
| return parse(input); | |
| }; | |
| export default { | |
| parseJson, | |
| }; | |
| const parseJson = (input, maxDepth = 100) => { | |
| const seen = new WeakSet(); | |
| const parse = (value, depth = 0) => { | |
| if (depth >= maxDepth) { | |
| return value; | |
| } | |
| if (typeof value === "string") { | |
| // Only parse if the string looks like a JSON object or array | |
| const trimmed = value.trim(); | |
| if ( | |
| (trimmed.startsWith("{") && trimmed.endsWith("}")) || | |
| (trimmed.startsWith("[") && trimmed.endsWith("]")) | |
| ) { | |
| try { | |
| return parse(JSON.parse(value), depth + 1); | |
| } catch (e) { | |
| return value; | |
| } | |
| } | |
| return value; | |
| } | |
| if (value && typeof value === "object") { | |
| if (seen.has(value)) { | |
| return value; | |
| } | |
| seen.add(value); | |
| if (Array.isArray(value)) { | |
| return value.map((item) => parse(item, depth + 1)); | |
| } | |
| return Object.fromEntries( | |
| Object.entries(value) | |
| .map(([key, val]) => [key, parse(val, depth + 1)]), | |
| ); | |
| } | |
| return value; | |
| }; | |
| return parse(input); | |
| }; | |
| export default { | |
| parseJson, | |
| }; |
| getSalesOrder({ | ||
| salesOrderId, opts, | ||
| } = {}) { | ||
| return this._makeRequest({ | ||
| path: `/salesOrder/${salesOrderId}`, | ||
| ...opts, | ||
| }); | ||
| }, | ||
| createSalesOrder(opts = {}) { | ||
| return this._makeRequest({ | ||
| method: "POST", | ||
| path: "/salesOrder", | ||
| ...opts, | ||
| }); | ||
| }, | ||
| updateSalesOrder({ | ||
| salesOrderId, opts, | ||
| } = {}) { | ||
| return this._makeRequest({ | ||
| method: "PATCH", | ||
| path: `/salesOrder/${salesOrderId}`, | ||
| ...opts, | ||
| }); | ||
| }, | ||
| deleteSalesOrder({ | ||
| salesOrderId, opts, | ||
| } = {}) { | ||
| return this._makeRequest({ | ||
| method: "DELETE", | ||
| path: `/salesOrder/${salesOrderId}`, | ||
| ...opts, | ||
| }); | ||
| }, | ||
| listInvoices(opts = {}) { | ||
| return this._makeRequest({ | ||
| path: "/invoice", | ||
| ...opts, | ||
| }); | ||
| }, | ||
| getInvoice({ | ||
| invoiceId, opts, | ||
| } = {}) { | ||
| return this._makeRequest({ | ||
| path: `/invoice/${invoiceId}`, | ||
| ...opts, | ||
| }); | ||
| }, | ||
| createInvoice(opts = {}) { | ||
| return this._makeRequest({ | ||
| method: "POST", | ||
| path: "/invoice", | ||
| ...opts, | ||
| }); | ||
| }, | ||
| updateInvoice({ | ||
| invoiceId, opts, | ||
| } = {}) { | ||
| return this._makeRequest({ | ||
| method: "PATCH", | ||
| path: `/invoice/${invoiceId}`, | ||
| ...opts, | ||
| }); | ||
| }, | ||
| deleteInvoice({ | ||
| invoiceId, opts, | ||
| } = {}) { | ||
| return this._makeRequest({ | ||
| method: "DELETE", | ||
| path: `/invoice/${invoiceId}`, | ||
| ...opts, | ||
| }); | ||
| }, |
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.
🧩 Analysis chain
🏁 Script executed:
cd components/netsuite && find . -name "*.mjs" -o -name "*.js" | head -20Repository: PipedreamHQ/pipedream
Length of output: 589
🏁 Script executed:
cd components/netsuite && ls -laRepository: PipedreamHQ/pipedream
Length of output: 441
🏁 Script executed:
cd components/netsuite && wc -l netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 85
🏁 Script executed:
cd components/netsuite && sed -n '180,280p' netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 2294
🏁 Script executed:
cd components/netsuite && grep -r "getSalesOrder\|updateSalesOrder\|getInvoice\|updateInvoice" --include="*.mjs" --include="*.js" -B 3 -A 3Repository: PipedreamHQ/pipedream
Length of output: 2781
🏁 Script executed:
cd components/netsuite && find . -name "actions" -o -name "actions.mjs" -o -name "*action*.mjs"Repository: PipedreamHQ/pipedream
Length of output: 74
🏁 Script executed:
cd components/netsuite && ls -la actions/ 2>/dev/null || find . -path "*action*" -type f | head -20Repository: PipedreamHQ/pipedream
Length of output: 827
🏁 Script executed:
cd components/netsuite && find . -type f -name "*.mjs" | head -20Repository: PipedreamHQ/pipedream
Length of output: 589
🏁 Script executed:
cd components/netsuite && cat -n netsuite.app.mjs | sed -n '1,50p'Repository: PipedreamHQ/pipedream
Length of output: 1802
🏁 Script executed:
cd components/netsuite && wc -l netsuite.app.mjs && echo "---" && head -100 netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 2884
🏁 Script executed:
cd components/netsuite && grep -n "actions\|propDefinitions" netsuite.app.mjs | head -20Repository: PipedreamHQ/pipedream
Length of output: 87
🏁 Script executed:
cd components/netsuite && sed -n '200,280p' netsuite.app.mjs | cat -nRepository: PipedreamHQ/pipedream
Length of output: 2344
🏁 Script executed:
cd components/netsuite && find . -type d -name actionsRepository: PipedreamHQ/pipedream
Length of output: 74
🏁 Script executed:
cd components/netsuite && ls -laRepository: PipedreamHQ/pipedream
Length of output: 441
🏁 Script executed:
cd components/netsuite && git ls-files | head -30Repository: PipedreamHQ/pipedream
Length of output: 576
🏁 Script executed:
git ls-files components/netsuite/ | head -40Repository: PipedreamHQ/pipedream
Length of output: 856
🏁 Script executed:
git ls-files components/netsuite/ | grep -E "\.(mjs|js)$"Repository: PipedreamHQ/pipedream
Length of output: 823
🏁 Script executed:
cat components/netsuite/netsuite.app.mjs | sed -n '200,280p'Repository: PipedreamHQ/pipedream
Length of output: 1777
🏁 Script executed:
cat components/netsuite/netsuite.app.mjs | grep -n "getSalesOrder\|getInvoice\|updateSalesOrder\|updateInvoice\|deleteSalesOrder\|deleteInvoice" | head -20Repository: PipedreamHQ/pipedream
Length of output: 211
🏁 Script executed:
wc -l components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 105
🏁 Script executed:
sed -n '200,300p' components/netsuite/netsuite.app.mjs | cat -nRepository: PipedreamHQ/pipedream
Length of output: 2913
🏁 Script executed:
rg "getSalesOrder|getInvoice|updateSalesOrder|updateInvoice" components/netsuite/ -A 2 -B 2Repository: PipedreamHQ/pipedream
Length of output: 2745
🏁 Script executed:
find components/netsuite -name "*action*" -type fRepository: PipedreamHQ/pipedream
Length of output: 47
🏁 Script executed:
ls -la components/netsuite/actions/Repository: PipedreamHQ/pipedream
Length of output: 827
🏁 Script executed:
cat components/netsuite/actions/getSalesOrder.mjsRepository: PipedreamHQ/pipedream
Length of output: 142
🏁 Script executed:
cat components/netsuite/actions/updateSalesOrder.mjsRepository: PipedreamHQ/pipedream
Length of output: 145
🏁 Script executed:
cat components/netsuite/actions/getInvoice.mjsRepository: PipedreamHQ/pipedream
Length of output: 139
🏁 Script executed:
sed -n '200,280p' components/netsuite/netsuite.app.mjs | cat -nRepository: PipedreamHQ/pipedream
Length of output: 2344
🏁 Script executed:
grep -n "getSalesOrder\|getInvoice\|updateSalesOrder" components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 136
🏁 Script executed:
sed -n '202,273p' components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 1599
🏁 Script executed:
cat components/netsuite/actions/updateSalesOrder.mjsRepository: PipedreamHQ/pipedream
Length of output: 145
🏁 Script executed:
cat components/netsuite/actions/updateInvoice.mjsRepository: PipedreamHQ/pipedream
Length of output: 142
🏁 Script executed:
rg "this\.app\." components/netsuite/actions/ -A 2 -B 2 | head -60Repository: PipedreamHQ/pipedream
Length of output: 47
🏁 Script executed:
cat components/netsuite/actions/getSalesOrder.mjsRepository: PipedreamHQ/pipedream
Length of output: 142
🏁 Script executed:
cat components/netsuite/actions/createSalesOrder.mjsRepository: PipedreamHQ/pipedream
Length of output: 145
🏁 Script executed:
sed -n '202,240p' components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 914
🏁 Script executed:
ast-grep --pattern $'getSalesOrder($_) {
$$$
}'Repository: PipedreamHQ/pipedream
Length of output: 47
🏁 Script executed:
python3 << 'EOF'
import re
with open('components/netsuite/netsuite.app.mjs', 'r') as f:
content = f.read()
# Find getSalesOrder method
match = re.search(r'getSalesOrder\([^)]*\)\s*\{[^}]*\}', content, re.DOTALL)
if match:
print("getSalesOrder signature:")
print(match.group(0)[:200])
print()
# Find updateSalesOrder
match = re.search(r'updateSalesOrder\([^)]*\)\s*\{[^}]*\}', content, re.DOTALL)
if match:
print("updateSalesOrder signature:")
print(match.group(0)[:200])
EOFRepository: PipedreamHQ/pipedream
Length of output: 151
🏁 Script executed:
head -280 components/netsuite/netsuite.app.mjs | tail -80 | cat -nRepository: PipedreamHQ/pipedream
Length of output: 2327
🏁 Script executed:
ls -1 components/netsuite/actions/Repository: PipedreamHQ/pipedream
Length of output: 226
🏁 Script executed:
cat components/netsuite/actions/getSalesOrder.mjsRepository: PipedreamHQ/pipedream
Length of output: 142
🏁 Script executed:
cat components/netsuite/actions/updateSalesOrder.mjsRepository: PipedreamHQ/pipedream
Length of output: 145
🏁 Script executed:
python3 << 'EOF'
import os
import re
actions_dir = 'components/netsuite/actions'
for filename in os.listdir(actions_dir):
if filename.endswith('.mjs'):
filepath = os.path.join(actions_dir, filename)
with open(filepath, 'r') as f:
content = f.read()
# Find calls to this.app
calls = re.findall(r'this\.app\.(\w+)\([^)]*\)', content)
if calls and any(x in ['getSalesOrder', 'updateSalesOrder', 'getInvoice', 'updateInvoice', 'deleteSalesOrder', 'deleteInvoice'] for x in calls):
print(f"\n{filename}:")
# Get the actual call
match = re.search(r'return this\.app\.(\w+)\(\s*\{[^}]*\}\s*\)', content, re.DOTALL)
if match:
full_match = re.search(r'return this\.app\.\w+\(\s*\{[^}]*\}\s*\)', content, re.DOTALL)
if full_match:
call_text = full_match.group(0)
# Limit display
print(call_text[:300] if len(call_text) < 300 else call_text[:300] + "...")
EOFRepository: PipedreamHQ/pipedream
Length of output: 151
🏁 Script executed:
cat components/netsuite/actions/updateSalesOrder.mjs | grep -A 20 "return this.app"Repository: PipedreamHQ/pipedream
Length of output: 145
🏁 Script executed:
cat components/netsuite/actions/updateInvoice.mjs | grep -A 20 "return this.app"Repository: PipedreamHQ/pipedream
Length of output: 142
🏁 Script executed:
python3 << 'EOF'
with open('components/netsuite/netsuite.app.mjs', 'r') as f:
lines = f.readlines()
# Print lines 202-240 with line numbers
for i in range(201, min(240, len(lines))):
print(f"{i+1}: {lines[i]}", end='')
EOFRepository: PipedreamHQ/pipedream
Length of output: 151
🏁 Script executed:
sed -n '100,200p' components/netsuite/netsuite.app.mjs | grep -A 30 "_makeRequest"Repository: PipedreamHQ/pipedream
Length of output: 390
🏁 Script executed:
grep -n "_makeRequest" components/netsuite/netsuite.app.mjs | head -5Repository: PipedreamHQ/pipedream
Length of output: 241
🏁 Script executed:
sed -n '50,150p' components/netsuite/netsuite.app.mjs | cat -nRepository: PipedreamHQ/pipedream
Length of output: 3701
🏁 Script executed:
head -100 components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 2859
🏁 Script executed:
cat components/netsuite/actions/updateSalesOrder.mjsRepository: PipedreamHQ/pipedream
Length of output: 145
🏁 Script executed:
python3 << 'EOF'
# Simulate the destructuring
call_obj = {
'$': 'context',
'salesOrderId': '123',
'data': {'field': 'value'}
}
# Current signature: updateSalesOrder({ salesOrderId, opts } = {})
def current_signature(**kwargs):
salesOrderId = kwargs.pop('salesOrderId', None)
opts = kwargs.pop('opts', None)
remaining = kwargs
print(f"salesOrderId: {salesOrderId}")
print(f"opts: {opts}")
print(f"remaining keys: {list(remaining.keys())}")
# Proposed signature: updateSalesOrder(opts = {})
def proposed_signature(opts={}):
salesOrderId = opts.pop('salesOrderId', None)
rest = opts
print(f"salesOrderId: {salesOrderId}")
print(f"rest keys: {list(rest.keys())}")
print("Current signature behavior:")
current_signature(**call_obj)
print("\nProposed signature behavior:")
proposed_signature(call_obj.copy())
EOFRepository: PipedreamHQ/pipedream
Length of output: 151
🏁 Script executed:
sed -n '1,100p' components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 2859
🏁 Script executed:
sed -n '180,220p' components/netsuite/netsuite.app.mjsRepository: PipedreamHQ/pipedream
Length of output: 1020
🏁 Script executed:
cat components/netsuite/actions/getSalesOrder.mjsRepository: PipedreamHQ/pipedream
Length of output: 142
🏁 Script executed:
cat components/netsuite/actions/getInvoice.mjsRepository: PipedreamHQ/pipedream
Length of output: 139
🏁 Script executed:
cat components/netsuite/actions/createSalesOrder.mjsRepository: PipedreamHQ/pipedream
Length of output: 145
🏁 Script executed:
rg "\.getSalesOrder\(|\.updateSalesOrder\(|\.getInvoice\(|\.updateInvoice\(" components/netsuite/ -B 2 -A 2Repository: PipedreamHQ/pipedream
Length of output: 1691
Update get/update/delete helpers to prevent silent discard of top-level options
The current helper signatures (e.g., getSalesOrder({ salesOrderId, opts } = {})) destructure salesOrderId and opts separately, but when actions call these methods with top-level parameters like { $, salesOrderId, data, params }, the $ and additional options are completely discarded because they don't match the destructuring pattern. This breaks SDK context flow and data transmission for PATCH/DELETE operations.
Refactor all six helpers to use a single opts parameter and extract the ID:
- getSalesOrder({
- salesOrderId, opts,
- } = {}) {
- return this._makeRequest({
- path: `/salesOrder/${salesOrderId}`,
- ...opts,
- });
- },
+ getSalesOrder(opts = {}) {
+ const {
+ salesOrderId,
+ ...rest
+ } = opts;
+ return this._makeRequest({
+ path: `/salesOrder/${salesOrderId}`,
+ ...rest,
+ });
+ },
@@
- updateSalesOrder({
- salesOrderId, opts,
- } = {}) {
- return this._makeRequest({
- method: "PATCH",
- path: `/salesOrder/${salesOrderId}`,
- ...opts,
- });
- },
- deleteSalesOrder({
- salesOrderId, opts,
- } = {}) {
- return this._makeRequest({
- method: "DELETE",
- path: `/salesOrder/${salesOrderId}`,
- ...opts,
- });
- },
+ updateSalesOrder(opts = {}) {
+ const {
+ salesOrderId,
+ ...rest
+ } = opts;
+ return this._makeRequest({
+ method: "PATCH",
+ path: `/salesOrder/${salesOrderId}`,
+ ...rest,
+ });
+ },
+ deleteSalesOrder(opts = {}) {
+ const {
+ salesOrderId,
+ ...rest
+ } = opts;
+ return this._makeRequest({
+ method: "DELETE",
+ path: `/salesOrder/${salesOrderId}`,
+ ...rest,
+ });
+ },
@@
- getInvoice({
- invoiceId, opts,
- } = {}) {
- return this._makeRequest({
- path: `/invoice/${invoiceId}`,
- ...opts,
- });
- },
+ getInvoice(opts = {}) {
+ const {
+ invoiceId,
+ ...rest
+ } = opts;
+ return this._makeRequest({
+ path: `/invoice/${invoiceId}`,
+ ...rest,
+ });
+ },
@@
- updateInvoice({
- invoiceId, opts,
- } = {}) {
- return this._makeRequest({
- method: "PATCH",
- path: `/invoice/${invoiceId}`,
- ...opts,
- });
- },
- deleteInvoice({
- invoiceId, opts,
- } = {}) {
- return this._makeRequest({
- method: "DELETE",
- path: `/invoice/${invoiceId}`,
- ...opts,
- });
- },
+ updateInvoice(opts = {}) {
+ const {
+ invoiceId,
+ ...rest
+ } = opts;
+ return this._makeRequest({
+ method: "PATCH",
+ path: `/invoice/${invoiceId}`,
+ ...rest,
+ });
+ },
+ deleteInvoice(opts = {}) {
+ const {
+ invoiceId,
+ ...rest
+ } = opts;
+ return this._makeRequest({
+ method: "DELETE",
+ path: `/invoice/${invoiceId}`,
+ ...rest,
+ });
+ },This ensures all parameters including $, data, params, and headers pass through to _makeRequest.
📝 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.
| getSalesOrder({ | |
| salesOrderId, opts, | |
| } = {}) { | |
| return this._makeRequest({ | |
| path: `/salesOrder/${salesOrderId}`, | |
| ...opts, | |
| }); | |
| }, | |
| createSalesOrder(opts = {}) { | |
| return this._makeRequest({ | |
| method: "POST", | |
| path: "/salesOrder", | |
| ...opts, | |
| }); | |
| }, | |
| updateSalesOrder({ | |
| salesOrderId, opts, | |
| } = {}) { | |
| return this._makeRequest({ | |
| method: "PATCH", | |
| path: `/salesOrder/${salesOrderId}`, | |
| ...opts, | |
| }); | |
| }, | |
| deleteSalesOrder({ | |
| salesOrderId, opts, | |
| } = {}) { | |
| return this._makeRequest({ | |
| method: "DELETE", | |
| path: `/salesOrder/${salesOrderId}`, | |
| ...opts, | |
| }); | |
| }, | |
| listInvoices(opts = {}) { | |
| return this._makeRequest({ | |
| path: "/invoice", | |
| ...opts, | |
| }); | |
| }, | |
| getInvoice({ | |
| invoiceId, opts, | |
| } = {}) { | |
| return this._makeRequest({ | |
| path: `/invoice/${invoiceId}`, | |
| ...opts, | |
| }); | |
| }, | |
| createInvoice(opts = {}) { | |
| return this._makeRequest({ | |
| method: "POST", | |
| path: "/invoice", | |
| ...opts, | |
| }); | |
| }, | |
| updateInvoice({ | |
| invoiceId, opts, | |
| } = {}) { | |
| return this._makeRequest({ | |
| method: "PATCH", | |
| path: `/invoice/${invoiceId}`, | |
| ...opts, | |
| }); | |
| }, | |
| deleteInvoice({ | |
| invoiceId, opts, | |
| } = {}) { | |
| return this._makeRequest({ | |
| method: "DELETE", | |
| path: `/invoice/${invoiceId}`, | |
| ...opts, | |
| }); | |
| }, | |
| getSalesOrder(opts = {}) { | |
| const { | |
| salesOrderId, | |
| ...rest | |
| } = opts; | |
| return this._makeRequest({ | |
| path: `/salesOrder/${salesOrderId}`, | |
| ...rest, | |
| }); | |
| }, | |
| createSalesOrder(opts = {}) { | |
| return this._makeRequest({ | |
| method: "POST", | |
| path: "/salesOrder", | |
| ...opts, | |
| }); | |
| }, | |
| updateSalesOrder(opts = {}) { | |
| const { | |
| salesOrderId, | |
| ...rest | |
| } = opts; | |
| return this._makeRequest({ | |
| method: "PATCH", | |
| path: `/salesOrder/${salesOrderId}`, | |
| ...rest, | |
| }); | |
| }, | |
| deleteSalesOrder(opts = {}) { | |
| const { | |
| salesOrderId, | |
| ...rest | |
| } = opts; | |
| return this._makeRequest({ | |
| method: "DELETE", | |
| path: `/salesOrder/${salesOrderId}`, | |
| ...rest, | |
| }); | |
| }, | |
| listInvoices(opts = {}) { | |
| return this._makeRequest({ | |
| path: "/invoice", | |
| ...opts, | |
| }); | |
| }, | |
| getInvoice(opts = {}) { | |
| const { | |
| invoiceId, | |
| ...rest | |
| } = opts; | |
| return this._makeRequest({ | |
| path: `/invoice/${invoiceId}`, | |
| ...rest, | |
| }); | |
| }, | |
| createInvoice(opts = {}) { | |
| return this._makeRequest({ | |
| method: "POST", | |
| path: "/invoice", | |
| ...opts, | |
| }); | |
| }, | |
| updateInvoice(opts = {}) { | |
| const { | |
| invoiceId, | |
| ...rest | |
| } = opts; | |
| return this._makeRequest({ | |
| method: "PATCH", | |
| path: `/invoice/${invoiceId}`, | |
| ...rest, | |
| }); | |
| }, | |
| deleteInvoice(opts = {}) { | |
| const { | |
| invoiceId, | |
| ...rest | |
| } = opts; | |
| return this._makeRequest({ | |
| method: "DELETE", | |
| path: `/invoice/${invoiceId}`, | |
| ...rest, | |
| }); | |
| }, |
🤖 Prompt for AI Agents
In components/netsuite/netsuite.app.mjs around lines 202 to 273, the
get/update/delete helpers (getSalesOrder, updateSalesOrder, deleteSalesOrder,
getInvoice, updateInvoice, deleteInvoice) currently destructure their ID and an
inner opts object which causes top-level options like $/data/params/headers to
be dropped; change each signature to accept a single opts = {} parameter, pull
the id from opts (e.g., const { salesOrderId } = opts or invoiceId for invoice
helpers) and then call this._makeRequest using the resolved path and spread the
entire opts so all top-level properties are forwarded (keep
method:"PATCH"/"DELETE" where applicable). Ensure you do not lose other opts
when building the request.
WHY
Resolves #7478
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.