-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Box new action #18001
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
Box new action #18001
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 3 Skipped Deployments
|
WalkthroughA new "Create Box Sign Request" action was introduced, enabling the creation of signature requests in Box via the Box API. Supporting utility functions were added for parsing JSON input, and a new API method was implemented in the Box app integration. The package version was incremented to reflect these additions. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CreateSignRequestAction
participant Utils
participant BoxApp
participant BoxAPI
User->>CreateSignRequestAction: Provide input properties
CreateSignRequestAction->>Utils: Parse signers and additional options
Utils-->>CreateSignRequestAction: Return parsed objects
CreateSignRequestAction->>BoxApp: Call createSignRequest(payload)
BoxApp->>BoxAPI: POST /sign_requests with payload
BoxAPI-->>BoxApp: Response with sign request data
BoxApp-->>CreateSignRequestAction: Return API response
CreateSignRequestAction-->>User: Export summary and response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~18 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changesNo out-of-scope changes were found. Poem
Note 🔌 MCP (Model Context Protocol) integration is now available in Early Access!Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context. ✨ 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 comments)
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: 2
🧹 Nitpick comments (3)
components/box/actions/create-sign-request/create-sign-request.mjs (3)
12-17
: Consider accepting object[] for signers to remove the need for manual JSON parsing.If supported in your component schema, switch
signers
toobject[]
so users can input structured data directly. Keeps UX clean and avoids parsing errors.- signers: { - type: "string[]", + signers: { + type: "object[]", label: "Signers", description: "Array of signers for the signature request. Each signer should be a JSON object with at least an email property. [See the documentation](https://developer.box.com/reference/post-sign-requests/#param-signers) for more information. Example: `{\"email\": \"[email protected]\", \"role\": \"signer\"}`", },
57-62
: Additional options passthrough is helpful — ensure callers don’t need to JSON-stringify nested objects.With
utils.parseObjectEntries
, nested strings won’t be deeply parsed. This is fine, but document that deeply-nested structures should be provided as objects (not strings) to avoid surprises.
76-85
: Improve parse error context for signers.Include the index of the failing signer to speed debugging.
- const parsedSigners = signers.map((signer) => { - try { + const parsedSigners = signers.map((signer, idx) => { + try { return typeof signer === "string" ? JSON.parse(signer) : signer; } catch (error) { - throw new ConfigurationError(`Error parsing signer as JSON: ${error}`); + throw new ConfigurationError(`Error parsing signer at index ${idx} as JSON: ${error}`); } });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (4)
components/box/actions/create-sign-request/create-sign-request.mjs
(1 hunks)components/box/box.app.mjs
(1 hunks)components/box/common/utils.mjs
(1 hunks)components/box/package.json
(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2024-12-12T19:23:09.039Z
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.
Applied to files:
components/box/package.json
📚 Learning: 2025-07-01T17:07:48.193Z
Learnt from: js07
PR: PipedreamHQ/pipedream#17375
File: components/zerobounce/actions/get-validation-results-file/get-validation-results-file.mjs:23-27
Timestamp: 2025-07-01T17:07:48.193Z
Learning: "dir" props in Pipedream components are hidden in the component form and not user-facing, so they don't require labels or descriptions for user clarity.
Applied to files:
components/box/package.json
📚 Learning: 2025-07-01T17:07:48.193Z
Learnt from: js07
PR: PipedreamHQ/pipedream#17375
File: components/zerobounce/actions/get-validation-results-file/get-validation-results-file.mjs:23-27
Timestamp: 2025-07-01T17:07:48.193Z
Learning: For "dir" props in Pipedream components, whether to mark them as optional depends on the action's file I/O behavior - if an action always writes files as output, the "dir" prop should not be marked as optional.
Applied to files:
components/box/common/utils.mjs
📚 Learning: 2024-10-30T15:24:39.294Z
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".
Applied to files:
components/box/actions/create-sign-request/create-sign-request.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: Publish TypeScript components
- GitHub Check: Verify TypeScript components
- GitHub Check: pnpm publish
- GitHub Check: Lint Code Base
🔇 Additional comments (4)
components/box/package.json (1)
3-3
: Semver bump looks appropriate for a new action.Minor bump from 0.4.x → 0.5.0 aligns with adding new functionality.
components/box/box.app.mjs (1)
322-328
: Add createSignRequest method — LGTM.POST to
/sign_requests
with passthrough args matches Box API. Consistent with existing request helpers.components/box/common/utils.mjs (1)
4-11
: Lightweight JSON parsing helper — LGTM.Simple and safe fallback behavior for non-JSON values.
components/box/actions/create-sign-request/create-sign-request.mjs (1)
105-111
: Summary export and return shape — LGTM.Clear summary with the sign request ID and returning the full response matches Pipedream conventions.
const data = { | ||
signers: parsedSigners, | ||
name, | ||
email_subject: emailSubject, | ||
email_message: emailMessage, | ||
redirect_url: redirectUrl, | ||
declined_redirect_url: declinedRedirectUrl, | ||
...(additionalOptions | ||
? utils.parseObjectEntries(additionalOptions) | ||
: {}), | ||
}; |
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.
Missing required source_files
— API will 400 without it.
Box’s POST /sign_requests requires source_files
(or an alternative like prefill_template
/draft_id
). The action doesn’t expose this, relying on additionalOptions
, which is easy to miss.
Add a dedicated, required prop for source files and map to the payload:
@@
props: {
app,
signers: {
type: "string[]",
label: "Signers",
description: "Array of signers for the signature request. Each signer should be a JSON object with at least an email property. [See the documentation](https://developer.box.com/reference/post-sign-requests/#param-signers) for more information. Example: `{\"email\": \"[email protected]\", \"role\": \"signer\"}`",
},
+ sourceFiles: {
+ type: "string[]",
+ label: "Source Files",
+ description: "Array of Box file IDs to include in the sign request.",
+ },
@@
async run({ $ }) {
const {
signers,
+ sourceFiles,
name,
parentFolder,
emailSubject,
emailMessage,
redirectUrl,
declinedRedirectUrl,
additionalOptions,
} = this;
@@
- const data = {
+ if (!Array.isArray(sourceFiles) || sourceFiles.length === 0) {
+ throw new ConfigurationError("At least one source file is required (sourceFiles).");
+ }
+
+ const data = {
signers: parsedSigners,
+ source_files: sourceFiles.map((id) => ({
+ id,
+ type: "file",
+ })),
name,
email_subject: emailSubject,
email_message: emailMessage,
redirect_url: redirectUrl,
declined_redirect_url: declinedRedirectUrl,
...(additionalOptions
? utils.parseObjectEntries(additionalOptions)
: {}),
};
If you prefer to keep additionalOptions
as the only path, at minimum validate that additionalOptions.source_files
exists and is non-empty, and throw a clear ConfigurationError
otherwise.
📝 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 data = { | |
signers: parsedSigners, | |
name, | |
email_subject: emailSubject, | |
email_message: emailMessage, | |
redirect_url: redirectUrl, | |
declined_redirect_url: declinedRedirectUrl, | |
...(additionalOptions | |
? utils.parseObjectEntries(additionalOptions) | |
: {}), | |
}; | |
// In the action definition: | |
props: { | |
app, | |
signers: { | |
type: "string[]", | |
label: "Signers", | |
description: "Array of signers for the signature request. Each signer should be a JSON object with at least an email property. [See the documentation](https://developer.box.com/reference/post-sign-requests/#param-signers) for more information. Example: `{\"email\": \"[email protected]\", \"role\": \"signer\"}`", | |
}, | |
sourceFiles: { | |
type: "string[]", | |
label: "Source Files", | |
description: "Array of Box file IDs to include in the sign request.", | |
}, | |
parentFolder: { | |
type: "string", | |
// ...other existing props... | |
}, | |
emailSubject: { | |
type: "string", | |
// ... | |
}, | |
emailMessage: { | |
type: "string", | |
// ... | |
}, | |
redirectUrl: { | |
type: "string", | |
// ... | |
}, | |
declinedRedirectUrl: { | |
type: "string", | |
// ... | |
}, | |
additionalOptions: { | |
type: "object", | |
// ... | |
}, | |
}, | |
async run({ $ }) { | |
const { | |
signers, | |
sourceFiles, | |
name, | |
parentFolder, | |
emailSubject, | |
emailMessage, | |
redirectUrl, | |
declinedRedirectUrl, | |
additionalOptions, | |
} = this; | |
// Validate required sourceFiles | |
if (!Array.isArray(sourceFiles) || sourceFiles.length === 0) { | |
throw new ConfigurationError( | |
"At least one source file is required (sourceFiles)." | |
); | |
} | |
const data = { | |
signers: parsedSigners, | |
source_files: sourceFiles.map((id) => ({ | |
id, | |
type: "file", | |
})), | |
name, | |
email_subject: emailSubject, | |
email_message: emailMessage, | |
redirect_url: redirectUrl, | |
declined_redirect_url: declinedRedirectUrl, | |
...(additionalOptions | |
? utils.parseObjectEntries(additionalOptions) | |
: {}), | |
}; | |
// ...rest of the implementation... | |
} |
🤖 Prompt for AI Agents
In components/box/actions/create-sign-request/create-sign-request.mjs around
lines 86 to 96, the payload for the Box API call is missing the required
source_files property, causing a 400 error. Add a dedicated required parameter
for source_files to the function and include it explicitly in the data object
sent to the API. Alternatively, if you want to keep using additionalOptions, add
validation to check that additionalOptions.source_files exists and is not empty,
and throw a ConfigurationError with a clear message if this validation fails.
parseObjectEntries(value = {}) { | ||
const obj = typeof value === "string" | ||
? JSON.parse(value) | ||
: value; | ||
return Object.fromEntries( | ||
Object.entries(obj).map(([ | ||
key, | ||
value, | ||
]) => [ | ||
key, | ||
optionalParseAsJSON(value), | ||
]), | ||
); | ||
}, |
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
Guard against invalid top-level JSON in parseObjectEntries.
If value
is a string and not valid JSON, JSON.parse
will throw and crash the action. Wrap parsing in try/catch and surface a clear configuration error.
-import constants from "./constants.mjs";
-import { getFileStreamAndMetadata } from "@pipedream/platform";
+import constants from "./constants.mjs";
+import { getFileStreamAndMetadata, ConfigurationError } from "@pipedream/platform";
@@
export default {
- parseObjectEntries(value = {}) {
- const obj = typeof value === "string"
- ? JSON.parse(value)
- : value;
+ parseObjectEntries(value = {}) {
+ let obj = value;
+ if (typeof value === "string") {
+ try {
+ obj = JSON.parse(value);
+ } catch (e) {
+ throw new ConfigurationError("Invalid JSON for Additional Options. Provide a valid JSON object.");
+ }
+ }
return Object.fromEntries(
Object.entries(obj).map(([
key,
value,
]) => [
key,
optionalParseAsJSON(value),
]),
);
},
📝 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.
parseObjectEntries(value = {}) { | |
const obj = typeof value === "string" | |
? JSON.parse(value) | |
: value; | |
return Object.fromEntries( | |
Object.entries(obj).map(([ | |
key, | |
value, | |
]) => [ | |
key, | |
optionalParseAsJSON(value), | |
]), | |
); | |
}, | |
import constants from "./constants.mjs"; | |
import { getFileStreamAndMetadata, ConfigurationError } from "@pipedream/platform"; | |
export default { | |
parseObjectEntries(value = {}) { | |
let obj = value; | |
if (typeof value === "string") { | |
try { | |
obj = JSON.parse(value); | |
} catch (e) { | |
throw new ConfigurationError( | |
"Invalid JSON for Additional Options. Provide a valid JSON object." | |
); | |
} | |
} | |
return Object.fromEntries( | |
Object.entries(obj).map(([key, value]) => [ | |
key, | |
optionalParseAsJSON(value), | |
]), | |
); | |
}, | |
// …other methods | |
}; |
🤖 Prompt for AI Agents
In components/box/common/utils.mjs around lines 13 to 26, the parseObjectEntries
function directly calls JSON.parse on a string input, which can throw an error
if the string is not valid JSON. To fix this, wrap the JSON.parse call in a
try/catch block, and if parsing fails, throw a clear and descriptive
configuration error to prevent the action from crashing unexpectedly.
Closes #17737
Note: unable to validate this due to the required scopes seemingly only being available for enterprise accounts
Not bumping other box component versions since none are being updated
Summary by CodeRabbit