Skip to content

Commit d07faa9

Browse files
committed
fix(triggers): match delivery liveness, switch every live row of a block, keep legacy route behavior
Live rows now use the delivery and editor deployment test (active version, or versionless deploy with no version id) and no longer filter on registration status, so the editor never shows a row the legacy toggle rejects. A block target switches all of its live rows in one transaction; a row id switches only that row. Disabling a completed schedule moves it to disabled again, a cron with no future run is a 400 with the legacy message, and same-workspace role denials keep their legacy 403 bodies.
1 parent 685fea3 commit d07faa9

9 files changed

Lines changed: 410 additions & 270 deletions

File tree

‎apps/docs/openapi-v2-workflows.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2669,7 +2669,7 @@
26692669
"patch": {
26702670
"operationId": "updateWorkflowTrigger",
26712671
"summary": "Update workflow trigger",
2672-
"description": "Enable or disable one trigger of the live deployment without redeploying. Requires workspace write access. Enabling resets `failedCount`, schedules the next run, and clears any polling backoff; a schedule with no future runs returns `409` and an invalid cron expression returns `400`. A permission group that blocks webhook triggers returns `403` when enabling a polling, internal-event, or webhook trigger. Requesting the current state changes nothing.\n\nDisabling only stops Sim from accepting the trigger; nothing is removed at the provider. Deliveries to a disabled webhook receive `404`, and some providers disable their subscription after repeated failures, which requires a redeploy to restore.\n\nOAuth scope: `api:write`.",
2672+
"description": "Enable or disable one trigger of the live deployment without redeploying. Requires workspace write access. Enabling resets `failedCount`, schedules the next run, and clears any polling backoff; a schedule whose cron expression is invalid or has no future runs returns `400`. A permission group that blocks webhook triggers returns `403` when enabling a polling, internal-event, or webhook trigger. Disabling a completed schedule marks it disabled. A block with several live rows switches them together. Requesting the current state changes nothing.\n\nDisabling only stops Sim from accepting the trigger; nothing is removed at the provider. Deliveries to a disabled webhook receive `404`, and some providers disable their subscription after repeated failures, which requires a redeploy to restore.\n\nOAuth scope: `api:write`.",
26732673
"x-sim-operation": "workflows.triggers.set_enabled",
26742674
"x-oauth-scope": "api:write",
26752675
"tags": ["Workflows"],

‎apps/sim/app/api/schedules/[id]/route.ts‎

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import { parseRequest } from '@/lib/api/server'
1010
import {
1111
createInternalResourceConcealmentPolicy,
1212
defineInternalJsonRoute,
13+
extendInternalErrorPolicy,
1314
internalErrorResponse,
1415
internalOrchestrationErrorPolicy,
1516
internalRateLimits,
1617
internalSessionAuth,
1718
} from '@/lib/api/server/routes'
1819
import { getSession } from '@/lib/auth'
20+
import { InsufficientWorkspacePermissionsError } from '@/lib/core/application'
1921
import { generateRequestId } from '@/lib/core/utils/request'
2022
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
2123
import { workflowOperations } from '@/lib/workflows/application/operations'
@@ -117,21 +119,30 @@ export const PUT = defineInternalJsonRoute({
117119
}),
118120
errorPolicy: createInternalResourceConcealmentPolicy({
119121
notFoundMessage: 'Schedule not found',
120-
base: {
121-
project: internalOrchestrationErrorPolicy.project,
122-
unhandled: () => internalErrorResponse(500, { error: 'Failed to update schedule' }),
123-
},
122+
base: extendInternalErrorPolicy(
123+
{
124+
project: internalOrchestrationErrorPolicy.project,
125+
unhandled: () => internalErrorResponse(500, { error: 'Failed to update schedule' }),
126+
},
127+
(error) =>
128+
error instanceof InsufficientWorkspacePermissionsError
129+
? internalErrorResponse(403, {
130+
error: 'Unauthorized: Access denied to write this workflow',
131+
})
132+
: null
133+
),
124134
}),
125135
parseOptions: {
126136
validationErrorResponse: () =>
127137
NextResponse.json({ error: 'Invalid request body' }, { status: 400 }),
128138
},
129139
mapInput: ({ params, body }) => ({
130-
target: { kind: 'schedule_row' as const, scheduleId: params.id },
140+
target: { kind: 'row' as const, table: 'schedule' as const, id: params.id },
131141
enabled: body.action === 'reactivate',
132142
}),
133143
useCase: setWorkflowTriggerEnabled,
134-
present: ({ trigger, changed }, { input }) => {
144+
present: ({ trigger, changes }, { input }) => {
145+
const changed = changes.length > 0
135146
if (!input.enabled) {
136147
return {
137148
message: changed ? 'Schedule disabled successfully' : 'Schedule is already disabled',

‎apps/sim/app/api/webhooks/[id]/route.ts‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@ import { parseRequest } from '@/lib/api/server'
1919
import {
2020
createInternalResourceConcealmentPolicy,
2121
defineInternalJsonRoute,
22+
extendInternalErrorPolicy,
23+
internalErrorResponse,
2224
internalOrchestrationErrorPolicy,
2325
internalRateLimits,
2426
internalSessionAuth,
2527
} from '@/lib/api/server/routes'
2628
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
29+
import { InsufficientWorkspacePermissionsError } from '@/lib/core/application'
2730
import { PlatformEvents } from '@/lib/core/telemetry'
2831
import { generateRequestId } from '@/lib/core/utils/request'
2932
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
@@ -110,10 +113,14 @@ export const PATCH = defineInternalJsonRoute({
110113
}),
111114
errorPolicy: createInternalResourceConcealmentPolicy({
112115
notFoundMessage: 'Webhook not found',
113-
base: internalOrchestrationErrorPolicy,
116+
base: extendInternalErrorPolicy(internalOrchestrationErrorPolicy, (error) =>
117+
error instanceof InsufficientWorkspacePermissionsError
118+
? internalErrorResponse(403, { error: 'Access denied' })
119+
: null
120+
),
114121
}),
115122
mapInput: ({ params, body }) => ({
116-
target: { kind: 'webhook_row' as const, webhookId: params.id },
123+
target: { kind: 'row' as const, table: 'webhook' as const, id: params.id },
117124
enabled: body.isActive,
118125
}),
119126
useCase: setWorkflowTriggerEnabled,

‎apps/sim/lib/api/contracts/v2/openapi/workflows.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -949,7 +949,7 @@ const declaredRoutes = [
949949
applicationOperation: workflowOperations.setTriggerEnabled,
950950
operationId: 'updateWorkflowTrigger',
951951
summary: 'Update workflow trigger',
952-
description: `Enable or disable one trigger of the live deployment without redeploying. Requires workspace write access. Enabling resets \`failedCount\`, schedules the next run, and clears any polling backoff; a schedule with no future runs returns \`409\` and an invalid cron expression returns \`400\`. A permission group that blocks webhook triggers returns \`403\` when enabling a polling, internal-event, or webhook trigger. Requesting the current state changes nothing.\n\nDisabling only stops Sim from accepting the trigger; nothing is removed at the provider. Deliveries to a disabled webhook receive \`404\`, and some providers disable their subscription after repeated failures, which requires a redeploy to restore.`,
952+
description: `Enable or disable one trigger of the live deployment without redeploying. Requires workspace write access. Enabling resets \`failedCount\`, schedules the next run, and clears any polling backoff; a schedule whose cron expression is invalid or has no future runs returns \`400\`. A permission group that blocks webhook triggers returns \`403\` when enabling a polling, internal-event, or webhook trigger. Disabling a completed schedule marks it disabled. A block with several live rows switches them together. Requesting the current state changes nothing.\n\nDisabling only stops Sim from accepting the trigger; nothing is removed at the provider. Deliveries to a disabled webhook receive \`404\`, and some providers disable their subscription after repeated failures, which requires a redeploy to restore.`,
953953
errors: [...RESOURCE_MUTATION_ERRORS, 'PayloadTooLarge'],
954954
success: jsonSuccess('The trigger after the update.'),
955955
}),

‎apps/sim/lib/webhooks/polling/utils.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ const POLL_TICK_TOLERANCE_MS = 10_000
2828
/** Ceiling on a source's own `Retry-After`, so a hostile feed cannot park a trigger for days. */
2929
const POLL_RETRY_AFTER_MAX_MS = 24 * 60 * 60_000
3030

31-
const POLL_BACKOFF_UNTIL_KEY = 'pollBackoffUntil'
32-
const POLL_SOURCE_FAILURES_KEY = 'pollSourceFailures'
31+
export const POLL_BACKOFF_UNTIL_KEY = 'pollBackoffUntil'
32+
export const POLL_SOURCE_FAILURES_KEY = 'pollSourceFailures'
3333

3434
/**
3535
* Whether a webhook is inside the backoff window {@link recordPollSourceFailure}

0 commit comments

Comments
 (0)