Skip to content

feat(doordash): add DoorDash Drive integration with 13 API operations#3838

Open
waleedlatif1 wants to merge 39 commits intostagingfrom
waleedlatif1/add-doordash
Open

feat(doordash): add DoorDash Drive integration with 13 API operations#3838
waleedlatif1 wants to merge 39 commits intostagingfrom
waleedlatif1/add-doordash

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

Summary

  • Add complete DoorDash Drive integration (delivery quotes, deliveries, businesses, stores)
  • 13 operations: create/accept quote, create/get/update/cancel delivery, create/list/update business, create/list/get/update store
  • JWT-based auth (HS256) via internal API route with jose library
  • Block with conditional subBlocks, advanced mode for optional fields, wandConfig on timestamp fields

Type of Change

  • New feature

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

waleedlatif1 and others added 30 commits February 16, 2026 00:36
…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
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Mar 30, 2026 1:56am

Request Review

@cursor
Copy link
Copy Markdown

cursor bot commented Mar 30, 2026

PR Summary

Medium Risk
Adds a new internal API route that generates and uses JWTs to call DoorDash Drive/Developer APIs, which is security-sensitive and could impact request signing/credential handling. Remaining changes are mostly content/config updates to surface the new integration in docs and the integrations catalog.

Overview
Adds a new DoorDash Drive integration surfaced across the docs and integrations catalog, including a new DoordashIcon, block type→icon mapping updates, and a new doordash docs page with all 13 operations.

Introduces an internal Next.js API proxy at apps/sim/app/api/tools/doordash/route.ts that validates requests via zod, generates short-lived HS256 JWTs with jose, forwards requests to DoorDash drive/v2 and developer/v1 endpoints for deliveries/quotes/businesses/stores, and normalizes responses into a consistent output shape.

Written by Cursor Bugbot for commit 10bfbb6. Configure here.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

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 }),
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Fix in Cursor Fix in Web

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 30, 2026

Greptile Summary

This 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 (/api/tools/doordash) signs JWT tokens on the server, dispatches the correct DoorDash endpoint per operation, and returns normalised output; 13 individual ToolConfig files wire each operation's params and transformResponse; a block definition with conditional sub-blocks provides the UI.

Key highlights:

  • JWT signing with jose correctly includes the required DoorDash header claims (kid, dd-ver: DD-JWT-V1) and a 5-minute expiry
  • Credentials use visibility: 'user-only' throughout, consistent with the project credential policy
  • Boolean fields (contactlessDropoff, dropoffRequiresSignature) are correctly represented as string dropdowns with empty-string defaults, and properly guarded against empty strings before being sent to DoorDash
  • encodeURIComponent is used consistently for all path parameters
  • Documentation covers all 13 operations with input/output tables

Issues found:

  • response.json() is called before response.ok is checked in the API route. On non-JSON error responses (e.g., HTML 502/503 from DoorDash infrastructure), the parse throws before the error-handling branch is reached, and the outer catch discards the real HTTP status, returning a generic 500.
  • orderValue and tip fields pass through the Zod schema as plain strings and are cast with Number() without any numeric validation. Non-numeric user input would produce NaN, serialised as null in the JSON body, yielding a confusing DoorDash API error.
  • dropoffContactSendNotifications defaults to 'true' (opt-in SMS), unlike the other boolean dropdowns which default to off. Users who never open the advanced section will unknowingly trigger SMS notifications on every delivery.

Confidence Score: 5/5

Safe 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

Filename Overview
apps/sim/app/api/tools/doordash/route.ts Core API proxy route that signs JWT tokens, builds per-operation DoorDash requests, and maps responses. Two P2 issues: response.json() called before response.ok check, and orderValue/tip not validated as numeric strings before Number() cast.
apps/sim/blocks/blocks/doordash.ts Block definition wiring 13 DoorDash operations to tool IDs with conditional sub-blocks and advanced-mode optional fields. dropoffContactSendNotifications defaults to 'true' (opt-in SMS) which may be unexpected for users who don't open the advanced section.
apps/sim/tools/doordash/types.ts Comprehensive type definitions and output property constants for all 13 DoorDash operations; correctly uses user-only visibility for credentials as per project rules.
apps/sim/tools/doordash/index.ts Clean barrel export of all 13 tool instances and re-exported types.
apps/sim/tools/registry.ts All 13 DoorDash tools properly registered in the tool registry.
apps/sim/blocks/registry.ts DoordashBlock correctly added to the block registry.
apps/docs/content/docs/en/tools/doordash.mdx Well-written documentation covering all 13 operations with input/output tables; two minor 'No description' entries for keyId and name fields but otherwise complete.

Sequence Diagram

sequenceDiagram
    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
Loading

Reviews (1): Last reviewed commit: "feat(doordash): add DoorDash Drive integ..." | Re-trigger Greptile

Comment on lines +352 to +365
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 }
)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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(),

Comment on lines +265 to +275
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'] },
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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:

Suggested change
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants