feat(doordash): add DoorDash Drive integration with 13 API operations#3838
feat(doordash): add DoorDash Drive integration with 13 API operations#3838waleedlatif1 wants to merge 39 commits intostagingfrom
Conversation
…keyboard shortcuts, audit logs
…rects to rewrites
…stash, algolia tools; isolated-vm robustness improvements, tables backend (#3271) * feat(tools): advanced fields for youtube, vercel; added cloudflare and dataverse tools (#3257) * refactor(vercel): mark optional fields as advanced mode Move optional/power-user fields behind the advanced toggle: - List Deployments: project filter, target, state - Create Deployment: project ID override, redeploy from, target - List Projects: search - Create/Update Project: framework, build/output/install commands - Env Vars: variable type - Webhooks: project IDs filter - Checks: path, details URL - Team Members: role filter - All operations: team ID scope Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(youtube): mark optional params as advanced mode Hide pagination, sort order, and filter fields behind the advanced toggle for a cleaner default UX across all YouTube operations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * added advanced fields for vercel and youtube, added cloudflare and dataverse block * addded desc for dataverse * add more tools * ack comment * more * ops --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat(tables): added tables (#2867) * updates * required * trashy table viewer * updates * updates * filtering ui * updates * updates * updates * one input mode * format * fix lints * improved errors * updates * updates * chages * doc strings * breaking down file * update comments with ai * updates * comments * changes * revert * updates * dedupe * updates * updates * updates * refactoring * renames & refactors * refactoring * updates * undo * update db * wand * updates * fix comments * fixes * simplify comments * u[dates * renames * better comments * validation * updates * updates * updates * fix sorting * fix appearnce * updating prompt to make it user sort * rm * updates * rename * comments * clean comments * simplicifcaiton * updates * updates * refactor * reduced type confusion * undo * rename * undo changes * undo * simplify * updates * updates * revert * updates * db updates * type fix * fix * fix error handling * updates * docs * docs * updates * rename * dedupe * revert * uncook * updates * fix * fix * fix * fix * prepare merge * readd migrations * add back missed code * migrate enrichment logic to general abstraction * address bugbot concerns * adhere to size limits for tables * remove conflicting migration * add back migrations * fix tables auth * fix permissive auth * fix lint * reran migrations * migrate to use tanstack query for all server state * update table-selector * update names * added tables to permission groups, updated subblock types --------- Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai> Co-authored-by: waleed <walif6@gmail.com> * fix(snapshot): changed insert to upsert when concurrent identical child workflows are running (#3259) * fix(snapshot): changed insert to upsert when concurrent identical child workflows are running * fixed ci tests failing * fix(workflows): disallow duplicate workflow names at the same folder level (#3260) * feat(tools): added redis, upstash, algolia, and revenuecat (#3261) * feat(tools): added redis, upstash, algolia, and revenuecat * ack comment * feat(models): add gemini-3.1-pro-preview and update gemini-3-pro thinking levels (#3263) * fix(audit-log): lazily resolve actor name/email when missing (#3262) * fix(blocks): move type coercions from tools.config.tool to tools.config.params (#3264) * fix(blocks): move type coercions from tools.config.tool to tools.config.params Number() coercions in tools.config.tool ran at serialization time before variable resolution, destroying dynamic references like <block.result.count> by converting them to NaN/null. Moved all coercions to tools.config.params which runs at execution time after variables are resolved. Fixed in 15 blocks: exa, arxiv, sentry, incidentio, wikipedia, ahrefs, posthog, elasticsearch, dropbox, hunter, lemlist, spotify, youtube, grafana, parallel. Also added mode: 'advanced' to optional exa fields. Closes #3258 * fix(blocks): address PR review — move remaining param mutations from tool() to params() - Moved field mappings from tool() to params() in grafana, posthog, lemlist, spotify, dropbox (same dynamic reference bug) - Fixed parallel.ts excerpts/full_content boolean logic - Fixed parallel.ts search_queries empty case (must set undefined) - Fixed elasticsearch.ts timeout not included when already ends with 's' - Restored dropbox.ts tool() switch for proper default fallback * fix(blocks): restore field renames to tool() for serialization-time validation Field renames (e.g. personalApiKey→apiKey) must be in tool() because validateRequiredFieldsBeforeExecution calls selectToolId()→tool() then checks renamed field names on params. Only type coercions (Number(), boolean) stay in params() to avoid destroying dynamic variable references. * improvement(resolver): resovled empty sentinel to not pass through unexecuted valid refs to text inputs (#3266) * fix(blocks): add required constraint for serviceDeskId in JSM block (#3268) * fix(blocks): add required constraint for serviceDeskId in JSM block * fix(blocks): rename custom field values to request field values in JSM create request * fix(trigger): add isolated-vm support to trigger.dev container builds (#3269) Scheduled workflow executions running in trigger.dev containers were failing to spawn isolated-vm workers because the native module wasn't available in the container. This caused loop condition evaluation to silently fail and exit after one iteration. - Add isolated-vm to build.external and additionalPackages in trigger config - Include isolated-vm-worker.cjs via additionalFiles for child process spawning - Add fallback path resolution for worker file in trigger.dev environment * fix(tables): hide tables from sidebar and block registry (#3270) * fix(tables): hide tables from sidebar and block registry * fix(trigger): add isolated-vm support to trigger.dev container builds (#3269) Scheduled workflow executions running in trigger.dev containers were failing to spawn isolated-vm workers because the native module wasn't available in the container. This caused loop condition evaluation to silently fail and exit after one iteration. - Add isolated-vm to build.external and additionalPackages in trigger config - Include isolated-vm-worker.cjs via additionalFiles for child process spawning - Add fallback path resolution for worker file in trigger.dev environment * lint * fix(trigger): update node version to align with main app (#3272) * fix(build): fix corrupted sticky disk cache on blacksmith (#3273) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Lakee Sivaraya <71339072+lakeesiv@users.noreply.github.com> Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai> Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
… fixes, removed retired models, hex integration
…ogle tasks and bigquery integrations, workflow lock
…gespeed insights, pagerduty
…, brandfetch, google meet
… pagination, memory improvements
… selectors for 14 blocks
…ory instrumentation
…aders, webhook trigger configs (#3530)
…anvas navigation updates
… block classifications
v0.6.8: mothership tool loop
…ty hardening, connectors improvements
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryMedium Risk Overview Introduces an internal Next.js API proxy at Written by Cursor Bugbot for commit 10bfbb6. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| }), | ||
| ...(body.pickupTime && { pickup_time: body.pickupTime }), | ||
| ...(body.dropoffTime && { dropoff_time: body.dropoffTime }), | ||
| } |
There was a problem hiding this comment.
Duplicated request body construction across two operations
Low Severity
The create_quote and create_delivery cases build an identical ~30-line request body object with the same fields, same conditionals, and same type conversions. A bug fix or field addition in one would need to be manually replicated in the other. Extracting a shared helper (e.g. buildDeliveryRequestBody) would eliminate this duplication.
Additional Locations (1)
Greptile SummaryThis PR adds a complete DoorDash Drive integration with 13 operations covering the full delivery lifecycle (quote → accept → track → update → cancel) plus business and store management. The architecture is consistent with other integrations in the codebase: a single internal API route ( Key highlights:
Issues found:
Confidence Score: 5/5Safe to merge; all remaining findings are P2 style/robustness suggestions that don't block correct operation in the happy path. The core logic — JWT generation, endpoint dispatch, credential handling, and tool wiring — is correct and consistent with existing integrations. The three flagged issues are all P2: the non-JSON error body edge case is caught by the outer try/catch (just with a less specific message), NaN would be rejected by DoorDash rather than silently corrupting data, and the SMS default is a UX consideration rather than a functional defect. apps/sim/app/api/tools/doordash/route.ts — response.json() ordering and missing numeric validation; apps/sim/blocks/blocks/doordash.ts — dropoffContactSendNotifications default value. Important Files Changed
Sequence DiagramsequenceDiagram
participant UI as Block UI
participant Executor as Workflow Executor
participant Route as /api/tools/doordash
participant DD as DoorDash API
UI->>Executor: Run block (operation, credentials, params)
Executor->>Executor: Resolve tool ID via tools.config.tool(params)
Executor->>Executor: Merge params via tools.config.params(inputs)
Executor->>Route: POST { operation, developerId, keyId, signingSecret, ...params }
Route->>Route: Zod validation
Route->>Route: generateJwt(developerId, keyId, signingSecret)
Note over Route: HS256, kid, dd-ver: DD-JWT-V1, exp: now+300s
Route->>DD: HTTP request (Bearer JWT) to DRIVE_V2 or DEVELOPER_V1
DD-->>Route: JSON response
Route->>Route: extractDeliveryOutput / extractBusinessOutput / extractStoreOutput
Route-->>Executor: { success, output }
Executor-->>UI: Block output
Reviews (1): Last reviewed commit: "feat(doordash): add DoorDash Drive integ..." | Re-trigger Greptile |
| const response = await fetch(url, fetchOptions) | ||
| const data = await response.json() | ||
|
|
||
| if (!response.ok) { | ||
| const errorMessage = | ||
| (data as Record<string, unknown>).message ?? | ||
| (data as Record<string, unknown>).error ?? | ||
| `DoorDash API error (${response.status})` | ||
| logger.error('DoorDash API error', { status: response.status, error: errorMessage }) | ||
| return NextResponse.json( | ||
| { success: false, error: String(errorMessage) }, | ||
| { status: response.status } | ||
| ) | ||
| } |
There was a problem hiding this comment.
response.json() called before response.ok check
response.json() is called unconditionally before the !response.ok guard. If DoorDash returns a non-JSON body (e.g., HTML on a 502/503 gateway error), response.json() will throw and control jumps to the outer catch, which returns a generic "Failed to communicate with DoorDash API" 500 — discarding the original HTTP status code and any meaningful error detail.
Consider reading the body as text first, then conditionally parsing as JSON:
const text = await response.text()
if (!response.ok) {
let errorMessage: string
try {
const errData = JSON.parse(text) as Record<string, unknown>
errorMessage = String(
errData.message ?? errData.error ?? `DoorDash API error (${response.status})`
)
} catch {
errorMessage = text || `DoorDash API error (${response.status})`
}
logger.error('DoorDash API error', { status: response.status, error: errorMessage })
return NextResponse.json(
{ success: false, error: errorMessage },
{ status: response.status }
)
}
const data = JSON.parse(text) as Record<string, unknown>| dropoff_address: body.dropoffAddress, | ||
| dropoff_phone_number: body.dropoffPhoneNumber, | ||
| dropoff_business_name: body.dropoffBusinessName, | ||
| order_value: Number(body.orderValue), |
There was a problem hiding this comment.
Number() cast without numeric validation — may produce NaN
Number(body.orderValue) is called without first validating that body.orderValue is a numeric string. If a user (or an LLM) passes a non-numeric value like "free", Number(...) returns NaN, which is serialised as null in JSON — causing a silent data issue in the DoorDash request body.
The same applies to Number(body.tip) on lines 185, 214, 234, and 269.
Consider adding a numeric refinement to the Zod schema:
orderValue: z.string().regex(/^\d+$/, 'Must be a whole number in cents').optional(),
tip: z.string().regex(/^\d+$/, 'Must be a whole number in cents').optional(),| id: 'dropoffContactSendNotifications', | ||
| title: 'Send SMS Notifications', | ||
| type: 'dropdown', | ||
| options: [ | ||
| { label: 'Yes', id: 'true' }, | ||
| { label: 'No', id: 'false' }, | ||
| ], | ||
| value: () => 'true', | ||
| mode: 'advanced', | ||
| condition: { field: 'operation', value: ['create_quote', 'create_delivery'] }, | ||
| }, |
There was a problem hiding this comment.
dropoffContactSendNotifications defaults to 'true' — may send unexpected SMS
The dropdown defaults to value: () => 'true', meaning SMS notifications to the recipient are enabled unless the user explicitly disables them. Unlike the other boolean dropdowns (contactlessDropoff, dropoffRequiresSignature) which default to '' (off), this one opts users in by default. Because it lives under mode: 'advanced', users who never open the advanced section will unknowingly trigger SMS notifications on every delivery.
If "opt-out" is preferred, change the default:
| id: 'dropoffContactSendNotifications', | |
| title: 'Send SMS Notifications', | |
| type: 'dropdown', | |
| options: [ | |
| { label: 'Yes', id: 'true' }, | |
| { label: 'No', id: 'false' }, | |
| ], | |
| value: () => 'true', | |
| mode: 'advanced', | |
| condition: { field: 'operation', value: ['create_quote', 'create_delivery'] }, | |
| }, | |
| value: () => '', |
…and add a { label: 'Default', id: '' } option so users can revert to the API default explicitly.


Summary
Type of Change
Testing
Tested manually
Checklist