fix(triggers): stop cloned trigger blocks reusing the source's webhook URL - #6091
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Adds
Reviewed by Cursor Bugbot for commit 14afed6. Configure here. |
Greptile SummaryClears stored
Confidence Score: 5/5This PR appears safe to merge; no blocking failures remain from prior review or the current clone-path fix. No blocking failure remains. The change narrowly clears cloned triggerPath in both structure and value map on paste and duplicate paths, with tests covering the bug shapes and intentional non-clears.
|
| Filename | Overview |
|---|---|
| apps/sim/stores/workflows/utils.ts | Introduces clearClonedWebhookPath and applies it after id regeneration so clones drop stored webhook paths. |
| apps/sim/stores/workflows/workflow/store.ts | Invokes the same clear on duplicateBlock so the store public API matches paste behavior. |
| apps/sim/stores/workflows/utils.test.ts | Covers clearing both stores of triggerPath and preserving webhookId/trigger config. |
| apps/sim/stores/workflows/workflow/store.test.ts | Covers duplicateBlock clearing triggerPath while keeping source identity and webhookId. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Copy/paste or duplicate block] --> B[regenerateBlockIds / duplicateBlock]
B --> C[clearClonedWebhookPath]
C --> D[Null triggerPath in subBlocks]
C --> E[Null triggerPath in value map]
D --> F[Clone derives URL from new block id]
E --> F
Reviews (2): Last reviewed commit: "fix(triggers): stop cloned trigger block..." | Re-trigger Greptile
…k URL Before a deploy, a trigger block's webhook URL is DERIVED — useWebhookManagement and the canvas both fall back to the block's own id, which cloning already regenerates, so copying an undeployed trigger yields a fresh URL. Deploy then registers the webhook at `path = triggerPath || block.id` and writes that literal path back into the source block's `triggerPath`. From then on the URL is STORED, and copy/paste copies it verbatim, so the clone renders the source's URL. Clear `triggerPath` on in-canvas clones so the clone derives a path from its new block id again. - Clears both the subBlocks structure and the sub-block value map: the value map is authoritative in mergeSubblockStateWithValues, and since no trigger declares `triggerPath` as a subblock it normally lives only in the store. - Deliberately unconditional and limited to `triggerPath`. No block declares that id, so there is nothing to collide with and no need to classify the block. - The sibling TRIGGER_RUNTIME_SUBBLOCK_IDS entries are left alone on purpose. `triggerConfig`/`triggerId` are user configuration. `webhookId` is a user-entered action field on Attio, Vercel, and Discord — and Attio/Vercel are trigger-capable, so clearing it by trigger-ness would destroy real config — while being unused as trigger state, since deploy mints its own row id and matches existing rows by block id. Scoped to the clone paths. No deploy-side, server-side, or import/export change.
df7a868 to
14afed6
Compare
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 14afed6. Configure here.
Summary
Copy/pasting or duplicating a deployed webhook trigger block gave the clone the source's webhook URL instead of a fresh one. The precondition is deploy, which is what made it look intermittent:
use-webhook-management.ts:103-109and the canvas both fall back to${baseUrl}/api/webhooks/trigger/${blockId}, and cloning already regenerates block ids — so copying an undeployed trigger yields a fresh URL on its own.path = triggerPath || block.id(deploy.ts:321-325) and the effect atuse-webhook-management.ts:151writes that literal path back into the source'striggerPath. Paste copies the string verbatim, the clone stops deriving, and it renders the source's URL.Fix: clear
triggerPathon in-canvas clones so the clone derives from its new block id again. Two lines of behavior, one new function.subBlocksstructure and the sub-block value map. The value map is authoritative inmergeSubblockStateWithValues(anullthere overrides the structure), and since no trigger declarestriggerPathas a subblock it normally lives only in the store. Clearing one without the other leaves the source's path in effect.triggerPath. Zero blocks declare that subblock id, so there is nothing to collide with and no need to classify the block first — no predicate, no gate.TRIGGER_RUNTIME_SUBBLOCK_IDSentries are left alone on purpose.triggerConfig/triggerIdare user configuration (andtriggerConfigcan be a legacy trigger's only config home).webhookIdis a user-entered action field on Attio, Vercel, and Discord — and Attio/Vercel are trigger-capable, so clearing it by trigger-ness would destroy real config — while being unused as trigger state: deploy mints its own row id viagenerateShortId()and matches existing rows by block id, anduseWebhookManagementoverwrites the field from the server anyway.Scope
Clone paths only. No deploy-side, server-side, or import/export behavior change —
regenerateWorkflowIds(export/import),sanitizeSubBlocksForDuplicate(server duplicate + workspace forking), and the copilot edit path are untouched.Type of Change
Testing
stores+lib+triggers(612 files);tsc --noEmitclean;check:boundaries,check:realtime-prune,check:client-boundary,check:api-validation,check:utilsall pass; biome clean.regenerateBlockIdscall siteduplicateBlockcall sitewebhookId(would wipe Attio/Vercel config)triggerConfig(would drop trigger setup)undefinedinstead ofnulltriggerMode: true(the shape the toolbar actually creates — confirmed against production rows) andtriggerMode: false(API/import rows), the value-map-only shape, the structure-only shape, and explicit preservation tests forwebhookIdon both a trigger-capable block in trigger mode and an action block.Checklist