* improvement(kb): deferred content fetching and metadata-based hashes for connectors
* fix(kb): remove message count from outlook contentHash to prevent list/get divergence
* fix(kb): increase outlook getDocument message limit from 50 to 250
* fix(kb): skip outlook messages without conversationId to prevent broken stubs
* fix(kb): scope outlook getDocument to same folder as listDocuments to prevent hash divergence
* fix(kb): add missing connector sync cron job to Helm values
The connector sync endpoint existed but had no cron job configured to trigger it,
meaning scheduled syncs would never fire.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review comments on staging release
- Add try/catch around clipboard.writeText() in CopyCodeButton
- Add missing folder and past_chat cases in resolveResourceFromContext
- Return 400 for ZodError instead of 500 in all 8 Athena API routes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(api): return 400 for Zod validation errors across 27 API routes
Routes using z.parse() were returning 500 for ZodError (client input
validation failures). Added instanceof z.ZodError check to return 400
before the generic 500 handler, matching the established pattern used
by 115+ other routes.
Affected services: CloudWatch (7), CloudFormation (7), DynamoDB (6),
Slack (3), Outlook (2), OneDrive (1), Google Drive (1).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(api): add success:false to ZodError responses for consistency
7 routes used { success: false, error: ... } in their generic error
handler but our ZodError handler only returned { error: ... }. Aligned
the ZodError response shape to match.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(polling): consolidate polling services into provider handler pattern
Eliminate self-POST anti-pattern and extract shared boilerplate from 4 polling
services into a clean handler registry mirroring lib/webhooks/providers/.
- Add processPolledWebhookEvent() to processor.ts for direct in-process webhook
execution, removing HTTP round-trips that caused Lambda 403/timeout errors
- Extract shared utilities (markWebhookFailed/Success, fetchActiveWebhooks,
runWithConcurrency, resolveOAuthCredential, updateWebhookProviderConfig)
- Create PollingProviderHandler interface with per-provider implementations
- Consolidate 4 identical route files into single dynamic [provider] route
- Standardize concurrency to 10 across all providers
- No infra changes needed — Helm cron paths resolve via dynamic route
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* polish(polling): extract lock TTL constant and remove unnecessary type casts
- Widen processPolledWebhookEvent body param to accept object, eliminating
`as unknown as Record<string, unknown>` double casts in all 4 handlers
- Extract LOCK_TTL_SECONDS constant in route, tying maxDuration and lock TTL
to a single value
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(polling): address PR review feedback
- Add archivedAt filters to fetchActiveWebhooks query, matching
findWebhookAndWorkflow in processor.ts to prevent polling archived
webhooks/workflows
- Move provider validation after auth check to prevent provider
enumeration by unauthenticated callers
- Fix inconsistent pollingIdempotency import path in outlook.ts to
match other handlers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(polling): use literal for maxDuration segment config
Next.js requires segment config exports to be statically analyzable
literals. Using a variable reference caused build failure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(admin): delete workspaces on ban
* Fix lint
* Wait until workspace deletion to return ban success
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* feat(athena): add AWS Athena integration
* fix(athena): address PR review comments
- Fix variable shadowing: rename inner `data` to `rowData` in row mapper
- Fix first-page maxResults off-by-one: request maxResults+1 to compensate for header row
- Add missing runtime guard for queryString in create_named_query
- Move athena registry entries to correct alphabetical position
* fix(athena): alphabetize registry keys and add type re-exports
- Reorder athena_* registry keys to strict alphabetical order
- Add type re-exports from index.ts barrel
* fix(athena): cap maxResults at 999 to prevent overflow with header row adjustment
The +1 adjustment for the header row on first-page requests could
produce MaxResults=1001 when user requests 1000, exceeding the AWS
API hard cap of 1000.
* feat(chat): drag workflows and folders from sidebar into chat input
* fix(chat): fix effectAllowed, stale atInsertPosRef, and drag-enter overlay for resource drags
* feat(chat): add task dragging and visible drag ghost for sidebar items
* feat(sidebar): add drag ghost with icons and task icon to context chips
* refactor(types): narrow ChatMessageContext.kind to ChatContextKind union and add workflowBorderColor utility
* feat(user-input): support Tab to select resource in mention dropdown
* fix(user-input): narrow ChatContext discriminated union before accessing workflowId
* fix(colors): overload workflowBorderColor to accept string | undefined
* fix(colors): simplify workflowBorderColor to single string | undefined signature
* fix(chat): remove resource panel tab when context mention is deleted from input
* fix(chat): use resource ID for context removal identity check
* fix(chat): add folder/task cases to resource resolver, task key to existingResourceKeys, and use workflowBorderColor in drag ghost
* revert(chat): remove folder/task from resolveResourceFromContext — no panel UI for these types
* fix(chat): add chatId to stored context types and workflow.color to drag callback deps
* fix(chat): guard chatId before adding task key to existingResourceKeys
* improvement(secrets): parallelize save mutations and add admin visibility for workspace secrets
* fix(secrets): sequence workspace upsert/delete to avoid read-modify-write race
* fix(secrets): use Promise.allSettled to ensure credential invalidation after all mutations settle
* feat(slack): add subtype field and signature verification to Slack trigger
* fix(slack): guard against NaN timestamp and align null/empty-string convention
* fix(docs): resolve missing tool outputs for spread-inherited V2 tools
* fix(docs): add word boundary to baseToolRegex to prevent false matches
* fix(docs): remove unnecessary case-insensitive flag from baseToolRegex
* feat(auth): add DISABLE_GOOGLE_AUTH and DISABLE_GITHUB_AUTH env vars
* fix(auth): also disable server-side OAuth provider registration when flags are set
* lint
* fix(modals): consistent text colors, copy, and workspace delete confirmation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(modal): replace useEffect with render-time state reset
Replace useEffect anti-pattern for resetting confirmation text with
React's recommended "adjusting state during render" pattern. This
ensures stale text is never painted and avoids an extra render cycle.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(knowledge): prevent navigation on context menu actions and widen tags modal
* fix(knowledge): guard onCopyId against navigation and use setTimeout for robustness
* refactor(knowledge): extract withActionGuard helper to deduplicate context menu guard
* fix(knowledge): wrap withActionGuard callback in try/finally to prevent stuck ref
* improvement(landing, blog): SEO and GEO optimization
* improvement(docs): ui/ux cleanup
* chore(blog): remove unused buildBlogJsonLd export and wordCount schema field
* fix(blog): stack related posts vertically on mobile and fill all suggestion slots
- Add flex-col sm:flex-row and matching border classes to related posts
nav for consistent mobile stacking with the main blog page
- Remove score > 0 filter in getRelatedPosts so it falls back to recent
posts when there aren't enough tag matches
- Align description text color with main page cards
The $contains filter operator builds an ILIKE pattern but does not
escape LIKE wildcard characters (%, _) in user-provided values.
This causes incorrect, over-broad query results when the search value
contains these characters. For example, filtering with
{ name: { $contains: "100%" } } matches any row where name
contains "100" followed by anything, not just the literal "100%".
Escape %, _, and \ in the value before interpolating into the ILIKE
pattern so that they match literally.
Co-authored-by: Waleed <walif6@gmail.com>
Co-authored-by: lawrence3699 <lawrence3699@users.noreply.github.com>
* fix(sso): default tokenEndpointAuthentication to client_secret_post
better-auth's SSO plugin does not URL-encode credentials before Base64
encoding in client_secret_basic mode (RFC 6749 §2.3.1). When the client
secret contains special characters (+, =, /), OIDC providers decode them
incorrectly, causing invalid_client errors.
Default to client_secret_post when tokenEndpointAuthentication is not
explicitly set to avoid this upstream encoding issue.
Fixes#3626
* fix(sso): use nullish coalescing and add env var for tokenEndpointAuthentication
- Use ?? instead of || for semantic correctness
- Add SSO_OIDC_TOKEN_ENDPOINT_AUTH env var so users can explicitly
set client_secret_basic when their provider requires it
* docs(sso): add SSO_OIDC_TOKEN_ENDPOINT_AUTH to script usage comment
Signed-off-by: Mini Jeong <mini.jeong@navercorp.com>
* fix(sso): validate SSO_OIDC_TOKEN_ENDPOINT_AUTH env var value
Replace unsafe `as` type cast with runtime validation to ensure only
'client_secret_post' or 'client_secret_basic' are accepted. Invalid
values (typos, empty strings) now fall back to undefined, letting the
downstream ?? fallback apply correctly.
Signed-off-by: Mini Jeong <mini.jeong@navercorp.com>
---------
Signed-off-by: Mini Jeong <mini.jeong@navercorp.com>
* refactor(triggers): consolidate v2 Linear triggers into same files as v1
Move v2 trigger exports from separate _v2.ts files into their
corresponding v1 files, matching the block v2 convention where
LinearV2Block lives alongside LinearBlock in the same file.
* updated
* fix: restore staging registry entries accidentally removed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs
* fix: restore integrations.json to staging version
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(generate-docs): extract all trigger configs from multi-export files
The buildTriggerRegistry function used a single regex exec per file,
which only captured the first TriggerConfig export. Files that export
both v1 and v2 triggers (consolidated same-file convention) had their
v2 triggers silently dropped from integrations.json.
Split each file into segments per export and parse each independently.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: restore staging linear handler and utils with teamId support
Restores the staging version of linear provider handler and trigger
utils that were accidentally regressed. Key restorations:
- teamId sub-block and allPublicTeams fallback in createSubscription
- Timestamp skew validation in verifyAuth
- actorType renaming in formatInput (avoids TriggerOutput collision)
- url field in formatInput and all output builders
- edited field in comment outputs
- externalId validation after webhook creation
- isLinearEventMatch returns false (not true) for unknown triggers
Adds extractIdempotencyId to the linear provider handler for webhook
deduplication support.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: restore non-Linear files accidentally modified
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: remove redundant extractIdempotencyId from linear handler
The idempotency service already uses the Linear-Delivery header
(which Linear always sends) as the primary dedup key. The body-based
fallback was unnecessary defensive code.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* idempotency
* tets
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(secrets): restore unsaved-changes guard for settings tab navigation
- Add useSettingsDirtyStore (stores/settings/dirty) to track dirty state across the settings sidebar and section components
- Wire credentials-manager and integrations-manager to sync dirty state to the store and clean up on unmount; also reset store synchronously in handleDiscardAndNavigate
- Update settings-sidebar to check dirty state before tab switches and Back navigation, showing an Unsaved Changes dialog if needed
- Remove dead stores/settings/environment directory; move EnvironmentVariable type into lib/environment/api
* fix(teams): harden Microsoft content URL validation
- Add isMicrosoftContentUrl helper with typed allowlist covering SharePoint, OneDrive, and Teams CDN domains
- Replace loose substring checks in Teams webhook handler with parsed-hostname matching to prevent bypass via partial domain names
- Deduplicate OneDrive share-link detection into isOneDriveShareLink flag and use searchParams API instead of string splitting
* fix(env): remove type re-exports from query file, drop keepPreviousData on static key
* fix(teams): remove smba.trafficmanager.net from Microsoft content allowlist
The subdomain check for smba.trafficmanager.net was unnecessary — Azure
Traffic Manager does not support nested subdomains of existing profiles,
but the pattern still raised a valid audit concern. Teams bot-framework
attachment URLs from this host fall through to the generic fetchWithDNSPinning
branch, which provides the same protection without the ambiguity.
* fix(secrets): guard active-tab re-click, restore keepPreviousData on workspace env query
* fix(teams): add 1drv.com apex to OneDrive share-link branch
1drv.com (apex) is a short-link domain functionally equivalent to
1drv.ms and requires share-token resolution, not direct fetch.
CDN subdomains (files.1drv.com) are unaffected — the exact-match
check leaves them on the direct-fetch path.
* fix(triggers): apply webhook audit follow-ups
Align the Greenhouse webhook matcher with provider conventions and clarify the Notion webhook secret setup text after the audit review.
Made-with: Cursor
* fix(webhooks): Salesforce provider handler, Zoom CRC and block wiring
Add salesforce WebhookProviderHandler with required shared secret auth,
matchEvent filtering, formatInput aligned to trigger outputs, and
idempotency keys. Require webhook secret and document JSON-only Flow
setup; enforce objectType when configured.
Zoom: pass raw body into URL validation signature check, try all active
webhooks on a path for secret match, add extractIdempotencyId, tighten
event matching for specialized triggers. Wire Zoom triggers into the
Zoom block. Extend handleChallenge with optional rawBody.
Register Salesforce pending verification probes for pre-save URL checks.
* fix(webhooks): harden Resend and Linear triggers (idempotency, auth, outputs)
- Dedupe Resend deliveries via svix-id and Linear via Linear-Delivery in idempotency keys
- Require Resend signing secret; validate createSubscription id and signing_secret
- Single source for Resend event maps in triggers/utils; fail closed on unknown trigger IDs
- Add raw event data to Resend trigger outputs and formatInput
- Linear: remove body-based idempotency key; timestamp skew after HMAC verify; format url and actorType
- Tighten isLinearEventMatch for unknown triggers; clarify generic webhook copy; fix header examples
- Add focused tests for idempotency headers and Linear matchEvent
* fix(webhooks): harden Vercel and Greenhouse trigger handlers
Require Vercel signing secret and validate x-vercel-signature; add
matchEvent with dynamic import, delivery idempotency, strict
createSubscription trigger IDs, and formatInput aligned to string IDs.
Greenhouse: dynamic import in matchEvent, strict unknown trigger IDs,
Greenhouse-Event-ID idempotency header, body fallback keys, clearer
optional secret copy. Update generic trigger wording and add tests.
* fix(gong): JWT verification, trigger UX, alignment script
- Optional RS256 verification when Gong JWT public key is configured (webhook_url + body_sha256 per Gong docs); URL secrecy when unset.
- Document that Gong rules filter calls; payload has no event type; add eventType + callId outputs for discoverability.
- Refactor Gong triggers to buildTriggerSubBlocks + shared JWT field; setup copy matches security model.
- Add check-trigger-alignment.ts (Gong bundled; extend PROVIDER_CHECKS for others) and update add-trigger guidance paths.
Made-with: Cursor
* fix(notion): align webhook lifecycle and outputs
Handle Notion verification requests safely, expose the documented webhook fields in the trigger contract, and update setup guidance so runtime data and user-facing configuration stay aligned.
Made-with: Cursor
* fix(webhooks): tighten remaining provider hardening
Close the remaining pre-merge caveats by tightening Salesforce, Zoom, and Linear behavior, and follow through on the deferred provider and tooling cleanup for Vercel, Greenhouse, Gong, and Notion.
Made-with: Cursor
* refactor(webhooks): move subscription helpers out of providers
Move provider subscription helpers alongside the subscription lifecycle module and add targeted TSDoc so the file placement matches the responsibility boundaries in the webhook architecture.
Made-with: Cursor
* fix(zoom): resolve env-backed secrets during validation
Use the same env-aware secret resolution path for Zoom endpoint validation as regular delivery verification so URL validation works correctly when the secret token is stored via env references.
Made-with: Cursor
* fix build
* consolidate tests
* refactor(salesforce): share payload object type parsing
Remove dead code in the Salesforce provider and move shared object-type extraction into a single helper so trigger matching and input shaping stay in sync.
Made-with: Cursor
* fix(webhooks): address remaining review follow-ups
Loosen Linear's replay window to better tolerate delayed retries and make Notion event mismatches return false consistently with the rest of the hardened providers.
Made-with: Cursor
* test(webhooks): separate Zoom coverage and clean Notion output shape
Move Zoom provider coverage into its own test file and strip undeclared Notion type fields from normalized output objects so the runtime shape better matches the trigger contract.
Made-with: Cursor
* feat(triggers): enrich Vercel and Greenhouse webhook output shapes
Document and pass through Vercel links, regions, deployment.meta, and
domain.delegated; add top-level Greenhouse applicationId, candidateId,
and jobId aligned with webhook common attributes. Extend alignment checker
for greenhouse, update provider docs, and add formatInput tests.
Made-with: Cursor
* feat(webhooks): enrich Resend trigger outputs; clarify Notion output docs
- Resend: expose broadcast_id, template_id, tags, and data_created_at from
payload data (per Resend webhook docs); keep alignment with formatInput.
- Add resend entry to check-trigger-alignment and unit test for formatInput.
- Notion: tighten output descriptions for authors, entity types, parent types,
attempt_number, and accessible_by per Notion webhooks event reference.
Made-with: Cursor
* feat(webhooks): enrich Zoom and Gong trigger output schemas
- Zoom: add formatInput passthrough, fix nested TriggerOutput shape (drop invalid `properties` wrappers), document host_email, join_url, agenda, status, meeting_type on recordings, participant duration, and alignment checker entry.
- Gong: flatten topics/highlights from callData.content in formatInput, extend metaData and trigger outputs per API docs, tests and alignment keys updated.
- Docs: add English webhook trigger sections for Zoom and Gong tools pages.
* feat(triggers): enrich Salesforce and Linear webhook output schemas
Salesforce: expose simEventType alongside eventType; pass OwnerId and
SystemModstamp on record lifecycle inputs; add AccountId/OwnerId for
Opportunity and AccountId/ContactId/OwnerId for Case. Align trigger
output docs with Flow JSON payloads and formatInput.
Linear: document actor email and profile url per official webhook
payload; add Comment data.edited from Linear's sample payload.
Tests: extend Salesforce formatInput coverage for new fields.
* remove from mdx
* chore(webhooks): expand trigger alignment coverage
Extend the trigger alignment checker to cover additional webhook providers so output contracts are verified across more of the recently added trigger surface.
Made-with: Cursor
* updated skills
* updated file naming semantics
* rename file
* feat(folders): soft-delete folders and show in Recently Deleted
Folders are now soft-deleted (archived) instead of permanently removed,
matching the existing pattern for workflows, tables, and knowledge bases.
Users can restore folders from Settings > Recently Deleted.
- Add `archivedAt` column to `workflowFolder` schema with index
- Change folder deletion to set `archivedAt` instead of hard-delete
- Add folder restore endpoint (POST /api/folders/[id]/restore)
- Batch-restore all workflows inside restored folders in one transaction
- Add scope filter to GET /api/folders (active/archived)
- Add Folders tab to Recently Deleted settings page
- Update delete modal messaging for restorable items
- Change "This action cannot be undone" styling to muted text
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(testing): add FOLDER_RESTORED to audit mock
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(folders): atomic restore transaction and scope to folder-deleted workflows
Address two review findings:
- Wrap entire folder restore in a single DB transaction to prevent
partial state if any step fails
- Only restore workflows archived within 5s of the folder's archivedAt,
so individually-deleted workflows are not silently un-deleted
- Add folder_restored to PostHog event map
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(folders): simplify restore to remove hacky 5s time window
The 5-second time window for scoping which workflows to restore was
a fragile heuristic (magic number, race-prone, non-deterministic).
Restoring a folder now restores all archived workflows in it, matching
standard trash/recycle-bin behavior. Users can re-delete any workflow
they don't want after restore.
The single-transaction wrapping from the prior commit is kept — that
was a legitimate atomicity fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(db): regenerate folder soft-delete migration with drizzle-kit
Replace manually created migration with proper drizzle-kit generated
one that includes the snapshot file, fixing CI schema sync check.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(db): fix migration metadata formatting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(folders): scope restore to folder-deleted workflows via shared timestamp
Use a single timestamp across the entire folder deletion — folders,
workflows, schedules, webhooks, etc. all get the exact same archivedAt.
On restore, match workflows by exact archivedAt equality with the
folder's timestamp, so individually-deleted workflows are not
silently un-deleted.
- Add optional archivedAt to ArchiveWorkflowOptions (backwards-compatible)
- Pass shared timestamp through deleteFolderRecursively → archiveWorkflowsByIdsInWorkspace
- Filter restore with eq(workflow.archivedAt, folderArchivedAt) instead of isNotNull
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(workflows): clear folderId on restore when folder is archived or missing
When individually restoring a workflow from Recently Deleted, check if
its folder still exists and is active. If the folder is archived or
missing, clear folderId so the workflow appears at root instead of
being orphaned (invisible in sidebar).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(folders): format restoreFolderRecursively call to satisfy biome
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(folders): close remaining restore edge cases
Three issues caught by audit:
1. Child folder restore used isNotNull instead of timestamp matching,
so individually-deleted child folders would be incorrectly restored.
Now uses eq(archivedAt, folderArchivedAt) for both workflows AND
child folders — consistent and deterministic.
2. No workspace archived check — could restore a folder into an
archived workspace. Now checks getWorkspaceWithOwner, matching
the existing restoreWorkflow pattern.
3. Re-restoring an already-restored folder returned an error. Now
returns success with zero counts (idempotent).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(folders): add archivedAt to optimistic folder creation objects
Ensures optimistic folder objects include archivedAt: null for
consistency with the database schema shape.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(folders): handle missing parent folder during restore reparenting
If the parent folder row no longer exists (not just archived), the
restored folder now correctly gets reparented to root instead of
retaining a dangling parentId reference.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(subflows): make edges inside subflows directly clickable
Edges inside subflows defaulted to z-index 0, causing the subflow body
area (pointer-events: auto) to intercept clicks. Derive edge z-index
from the container's depth so edges sit just above their parent container
but below canvas blocks and child blocks.
* Fix edge deletion in nested subflows
* Fix bug with multi selecting nested subblock
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* feat(home): add folders to resource menu
* fix(home): add folder to API validation and dedup logic
* fix(home): add folder context processing and generic title dedup
* fix(home): add folder icon to mention chip overlay
* fix(home): add folder to AgentContextType and context persistence
* fix(home): add workspace scoping to folder resolver, fix folderId type and dedup
* user message
* fix(copilot): fix copilot running workflow stuck on 10mb error
* Use correct try catch
* Add const
* Strip only logs on payload too large
* Fix threshold
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* Add credential prompting for google service accounts
* Add service account credential block prompting for google service account
* Revert requiredCredentials change
* Fix lint
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* fix(signup): show multiple signup errors at once
* Fix reset password error formatting
* Remove dead code
* Fix unit tests
---------
Co-authored-by: Theodore Li <theo@sim.ai>
* feat(triggers): add Linear v2 triggers with automatic webhook registration
* fix(triggers): preserve specific Linear API error messages in catch block
* fix(triggers): check response.ok before JSON parsing, replace as any with as unknown
* fix linear subscription params
* fix build
---------
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
* feat(triggers): add Zoom webhook triggers with challenge-response and signature verification
Add 6 Zoom webhook triggers (meeting started/ended, participant joined/left, recording completed, generic webhook) with full Zoom protocol support including endpoint.url_validation challenge-response handling and x-zm-signature HMAC-SHA256 verification.
* fix(triggers): use webhook.isActive instead of non-existent deletedAt column
* fix(triggers): address PR review feedback for Zoom webhooks
- Add 30s timestamp freshness check to prevent replay attacks
- Return null from handleChallenge when no secret token found instead of responding with empty-key HMAC
- Remove all `as any` casts from output builder functions
* lint
* fix(triggers): harden Zoom webhook security per PR review
- verifyAuth now fails closed (401) when secretToken is missing
- handleChallenge DB query filters by provider='zoom' to avoid cross-provider leaks
- handleChallenge verifies x-zm-signature before responding to prevent HMAC oracle
* fix(triggers): rename type to meeting_type to avoid TriggerOutput type collision
* fix(triggers): make challenge signature verification mandatory, not optional
* fix(triggers): fail closed on unknown trigger IDs and update Zoom landing page data
- isZoomEventMatch now returns false for unrecognized trigger IDs
- Update integrations.json with 6 Zoom triggers
* fix(triggers): add missing id fields to Zoom trigger entries in integrations.json
* fix(triggers): increase Zoom timestamp tolerance to 300s per Zoom docs