Skip to content

feat(sdk,slack): webhook sources, agent channels, and human-in-the-loop - #4537

Draft
ericallam wants to merge 13 commits into
feat/hosted-webhook-ingressfrom
feat/hosted-webhooks-api
Draft

feat(sdk,slack): webhook sources, agent channels, and human-in-the-loop#4537
ericallam wants to merge 13 commits into
feat/hosted-webhook-ingressfrom
feat/hosted-webhooks-api

Conversation

@ericallam

@ericallam ericallam commented Aug 8, 2026

Copy link
Copy Markdown
Member

Summary

The public SDK and docs half of hosted webhooks: webhook() with typed provider sources (webhooks.stripe(), webhooks.github(), webhooks.svix(), and more, plus webhooks.custom<T>()), chat.event and chat.channels for agent channels, human-in-the-loop tool approvals, the new @trigger.dev/slack connector, and the webhooks docs section.

import { webhook, webhooks } from "@trigger.dev/sdk";

export const stripeWebhook = webhook({
  id: "stripe-webhook",
  source: webhooks.stripe(),
  onEvent: async ({ event, headers, ctx }) => {
    // verified, typed Stripe event
  },
});

Stacked on the server PR

This is the top of a stack. Its base is #4344 (the server half: ingress, delivery pipeline, dashboard, and the shared @trigger.dev/core schemas this SDK builds on), so the diff here is API-only and it builds against a base that already has core.

The single changeset in this PR bumps @trigger.dev/core, @trigger.dev/sdk, @trigger.dev/slack, and trigger.dev together, so core (whose code lands via #4344) is published alongside the SDK.

Merge order

Merges after #4344. The plan: land and deploy the server behind its flag, cut prerelease (rc) packages for early users to test against the live environment, then merge this and cut the real release once the feature is live. When #4344 merges, GitHub retargets this PR's base to main automatically.

@changeset-bot

changeset-bot Bot commented Aug 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4b55ab5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 30 packages
Name Type
@trigger.dev/core Minor
@trigger.dev/sdk Minor
@trigger.dev/slack Minor
trigger.dev Minor
@trigger.dev/build Minor
@trigger.dev/python Minor
@trigger.dev/redis-worker Minor
@trigger.dev/schema-to-json Minor
@internal/cache Patch
@internal/clickhouse Patch
@internal/llm-model-catalog Patch
@internal/metrics-pipeline Patch
@trigger.dev/rbac Minor
@internal/redis Patch
@internal/replication Patch
@internal/run-engine Patch
@internal/run-store Patch
@internal/schedule-engine Patch
@trigger.dev/sso Minor
@internal/testcontainers Patch
@internal/tracing Patch
@internal/tsql Patch
@internal/webhook-engine Patch
@internal/webhook-sources Patch
@internal/dashboard-agent Patch
@internal/sdk-compat-tests Patch
@trigger.dev/react-hooks Minor
@trigger.dev/rsc Minor
@trigger.dev/database Minor
@trigger.dev/otlp-importer Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b169c3d1-b72b-4226-b637-c0754a0f224c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Added typed webhook sources, provider verification, webhook tasks, and durable chat.event routing. Extended chat agents with channel connectors, streaming replies, reactions, recovery handling, and human-in-the-loop controls. Added the Slack connector package with API operations and tests. Propagated webhook metadata through CLI manifests. Added documentation for webhook setup, filtering, deliveries, session routing, channels, and approvals.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description explains the changes and merge plan but omits most required template sections, including testing and changelog details. Add the issue closure, checklist, testing steps, changelog, and screenshots sections, and complete each section or state why it does not apply.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main SDK, webhook, Slack channel, and human-in-the-loop changes.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/hosted-webhooks-api

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread packages/slack/src/index.ts Fixed
Comment on lines +309 to +313
return key.replace(/\{([^}]+)\}/g, (_match, path: string) =>
path.startsWith("webhook.") || path.startsWith("header.") || path.startsWith("body.")
? `{${path}}`
: `{body.${path}}`
);

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 14

🧹 Nitpick comments (9)
packages/slack/src/index.ts (3)

279-283: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Check the response_url response.

The code ignores the fetch result. If Slack rejects the replace (expired response_url, invalid blocks, or a non-2xx status), the buttons stay live and clickable, and no signal reaches the caller.

The connector contract treats a throw here as best-effort and logs it. Throw on failure so the outcome is visible.

♻️ Proposed change
-  await fetch(responseUrl, {
+  const res = await fetch(responseUrl, {
     method: "POST",
     headers: { "content-type": "application/json" },
     body: JSON.stringify({ replace_original: true, text: `${decision}${who}`, blocks }),
   });
+  if (!res.ok) {
+    throw new Error(`slack response_url replace failed: ${res.status}`);
+  }

356-368: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Handle Slack rate limiting in makeSlackSend.

The code retries only on an auth error and only when token is a function. Slack rate-limits chat.postMessage and chat.update per channel (about one message per second, with Retry-After). With delivery: "stream", debounced edits reach that limit quickly. Each ratelimited response then throws and fails the turn.

Add a bounded retry with a delay for ratelimited.

♻️ Proposed change
     let result = await post();
     // Re-resolve once on an auth error (token rotation) when a resolver was supplied.
     if (!result.ok && typeof token === "function" && isAuthError(result.error)) {
       botToken = await resolve();
       result = await post();
     }
+    // Slack rate limits chat.* per channel; retry a bounded number of times.
+    for (let attempt = 0; attempt < 3 && !result.ok && result.error === "ratelimited"; attempt++) {
+      await new Promise((r) => setTimeout(r, (result.retryAfterSeconds ?? 1) * 1000));
+      result = await post();
+    }

400-408: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Check the HTTP status before you parse the body.

slackApi calls res.json() for every response. Slack returns a non-JSON body for some non-2xx responses, for example a 429 or a 5xx from the edge. res.json() then rejects with a parse error, and the caller reports that instead of the real status. The retry-after header is also lost.

Return a structured error for a non-2xx response.

♻️ Proposed change
 async function slackApi(
   baseUrl: string,
   method: string,
   token: string,
   body: Record<string, unknown>
-): Promise<{ ok: boolean; ts?: string; error?: string }> {
+): Promise<{ ok: boolean; ts?: string; error?: string; retryAfterSeconds?: number }> {
   const res = await fetch(`${baseUrl}/${method}`, {
     method: "POST",
     headers: {
       "content-type": "application/json; charset=utf-8",
       authorization: `Bearer ${token}`,
     },
     body: JSON.stringify(body),
   });
+  if (!res.ok) {
+    const retryAfter = Number(res.headers?.get?.("retry-after"));
+    return {
+      ok: false,
+      error: res.status === 429 ? "ratelimited" : `http_${res.status}`,
+      retryAfterSeconds: Number.isFinite(retryAfter) ? retryAfter : undefined,
+    };
+  }
   return (await res.json()) as { ok: boolean; ts?: string; error?: string };
 }

Note: the test doubles in packages/slack/src/index.test.ts return objects with only a json method. Add ok: true (and headers) to those doubles if you apply this change.

packages/slack/package.json (1)

43-48: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider moving @trigger.dev/core to devDependencies.

packages/slack/src/index.ts imports from @trigger.dev/core/v3 with import type only. No runtime value comes from core. Keeping core as a runtime dependency lets a consumer install a second core copy next to the one that @trigger.dev/sdk already pulls in.

If no runtime import appears later, move it to devDependencies, or add it as a peer alongside @trigger.dev/sdk.

packages/slack/src/index.test.ts (2)

11-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Restore globals in afterEach.

Each test calls vi.unstubAllGlobals() as its last statement. If an assertion fails first, or an awaited call rejects, that statement never runs. The fetch stub then leaks into the following tests, and one failure cascades into unrelated failures.

Move the cleanup into an afterEach hook and remove the per-test calls.

♻️ Proposed change
-import { describe, expect, it, vi } from "vitest";
+import { afterEach, describe, expect, it, vi } from "vitest";
 import { mentions, slack, toSlackMrkdwn, type SlackMessageEvent } from "./index.js";
@@
 describe("slack channel", () => {
+  afterEach(() => {
+    vi.unstubAllGlobals();
+  });
+

250-260: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a test for the token-resolver retry path.

makeSlackSend in packages/slack/src/index.ts re-resolves the token and retries once when the token is a function and the first call returns an auth error (lines 356-361). No test covers that branch, and no test covers a function-valued token.

Add a case where token is a resolver, the first response is { ok: false, error: "invalid_auth" }, and the second succeeds. Assert two fetch calls and the second authorization header.

Do you want me to write that test?

packages/trigger-sdk/src/v3/webhooks.ts (1)

345-359: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace the 14 repeated members with one typeof webhookSources.

Each member restates typeof webhookSources.X, and lines 368-381 restate the same 14 keys again. Any new producer requires three edits. An intersection keeps the list in one place.

♻️ Proposed refactor
   /** Header name used for webhook signatures */
   SIGNATURE_HEADER_NAME: string;
-  custom: typeof webhookSources.custom;
-  stripe: typeof webhookSources.stripe;
-  github: typeof webhookSources.github;
-  svix: typeof webhookSources.svix;
-  square: typeof webhookSources.square;
-  discord: typeof webhookSources.discord;
-  clerk: typeof webhookSources.clerk;
-  resend: typeof webhookSources.resend;
-  openai: typeof webhookSources.openai;
-  replicate: typeof webhookSources.replicate;
-  recallai: typeof webhookSources.recallai;
-  brex: typeof webhookSources.brex;
-  gitlab: typeof webhookSources.gitlab;
-  whatsapp: typeof webhookSources.whatsapp;
 }

Then declare the instance as Webhooks & ProviderProducers & typeof webhookSources and spread ...webhookSources in place of the 14 assignments.

packages/trigger-sdk/src/v3/ai.ts (1)

4793-4832: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Declare ChannelConnector as a type alias.

Every sibling in this block is a type. ChannelConnector is a data descriptor built by factory functions, not a behavioral contract that a class implements, so the repository rule applies.

Based on learnings, keep interface only for method-shape contracts that collaborators implement; this is a data shape.

As per coding guidelines: "Use types over interfaces for TypeScript".

♻️ Proposed change
-export interface ChannelConnector<TEvent = unknown> {
+export type ChannelConnector<TEvent = unknown> = {
   id: string;

Close with }; instead of }.

Sources: Coding guidelines, Learnings

packages/trigger-sdk/src/v3/channelReactions.test.ts (1)

9-15: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add a case for a resolver that throws.

resolveReactionChoice awaits a user-supplied function and does not catch. The tests cover undefined, null, "", and [], but not a throw.

The behavior matters at the call sites. At packages/trigger-sdk/src/v3/ai.ts line 6991 the call sits inside the turn try, so a throw becomes a turn error. At line 8305 the call runs after the turn already completed, and at line 8578 it runs inside the error handler. A throwing reactions.done or reactions.error resolver escapes there.

Every other reaction step is best-effort: applyChannelReaction catches and logs. Make resolveReactionChoice match, then assert it here.

💚 Proposed test and matching guard
   it("skips when absent or empty", async () => {
     expect(await resolveReactionChoice(undefined, {})).toBeUndefined();
     expect(await resolveReactionChoice("", {})).toBeUndefined();
     expect(await resolveReactionChoice([], {})).toBeUndefined();
     expect(await resolveReactionChoice(() => undefined, {})).toBeUndefined();
     expect(await resolveReactionChoice(() => null, {})).toBeUndefined();
   });
+
+  it("skips when the resolver throws", async () => {
+    expect(
+      await resolveReactionChoice(() => {
+        throw new Error("boom");
+      }, {})
+    ).toBeUndefined();
+  });

In packages/trigger-sdk/src/v3/ai.ts:

 export async function resolveReactionChoice(
   choice: ChannelReactionChoice | undefined,
   event: unknown
 ): Promise<string | undefined> {
   if (choice == null) return undefined;
-  let value: string | string[] | null | undefined =
-    typeof choice === "function" ? await choice(event) : choice;
+  let value: string | string[] | null | undefined;
+  try {
+    value = typeof choice === "function" ? await choice(event) : choice;
+  } catch (error) {
+    logger.warn("chat.agent: reaction resolver threw; skipping reaction", { error });
+    return undefined;
+  }

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 30f7bd73-ce46-4805-a3fb-8bb30dc30f3f

📥 Commits

Reviewing files that changed from the base of the PR and between c526528 and b4b9f89.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (25)
  • .changeset/hosted-webhook-ingress.md
  • docs/ai-chat/backend.mdx
  • docs/ai-chat/reference.mdx
  • docs/docs.json
  • docs/webhooks/channels.mdx
  • docs/webhooks/connect.mdx
  • docs/webhooks/deliveries.mdx
  • docs/webhooks/filters.mdx
  • docs/webhooks/human-in-the-loop.mdx
  • docs/webhooks/overview.mdx
  • docs/webhooks/session-routing.mdx
  • docs/webhooks/sources.mdx
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/package.json
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/slack/tsconfig.json
  • packages/slack/tsconfig.src.json
  • packages/slack/vitest.config.ts
  • packages/trigger-sdk/src/v3/ai.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (8)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (5, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (11, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (2, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (8, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (6, 12)
  • GitHub Check: sdk-compat / Bun Runtime
  • GitHub Check: packages / 🧪 Unit Tests: Packages (3, 3)
  • GitHub Check: e2e-webapp / 🧪 E2E Tests: Webapp
🧰 Additional context used
📓 Path-based instructions (13)
**/tsconfig.json

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use strict mode in TypeScript configuration

Files:

  • packages/slack/tsconfig.json
docs/**/docs.json

📄 CodeRabbit inference engine (docs/CLAUDE.md)

docs/**/docs.json: Main documentation config must be defined in docs.json which includes navigation structure, theme, and metadata
Navigation structure in docs.json should be organized using navigation.dropdowns with groups and pages

Files:

  • docs/docs.json
docs/**/*.mdx

📄 CodeRabbit inference engine (docs/CLAUDE.md)

docs/**/*.mdx: MDX documentation pages must include frontmatter with title (required), description (required), and sidebarTitle (optional) in YAML format
Use Mintlify components for structured content: , , , , , , /, /
Always import from @trigger.dev/sdk in code examples (never from @trigger.dev/sdk/v3)
Code examples must be complete and runnable where possible
Use language tags in code fences: typescript, bash, json

Documentation in docs/ uses MDX conventions defined by the documentation guidance.

Files:

  • docs/webhooks/connect.mdx
  • docs/webhooks/deliveries.mdx
  • docs/webhooks/human-in-the-loop.mdx
  • docs/webhooks/overview.mdx
  • docs/webhooks/filters.mdx
  • docs/ai-chat/reference.mdx
  • docs/webhooks/session-routing.mdx
  • docs/webhooks/channels.mdx
  • docs/webhooks/sources.mdx
  • docs/ai-chat/backend.mdx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: Prefer static imports over dynamic import(); use dynamic imports only for unresolvable circular dependencies, genuine performance code splitting, or conditional runtime loading.
Import Trigger.dev tasks from @trigger.dev/sdk; never use @trigger.dev/sdk/v3 or deprecated client.defineJob.
Add agentcrumbs while writing code using approved namespaces; mark lines with // @Crumbs or blocks with `// `#region` `@crumbs, and strip them before merging.

Files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/vitest.config.ts
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/vitest.config.ts
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)

**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries

Files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/vitest.config.ts
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
packages/cli-v3/src/entryPoints/**/*

📄 CodeRabbit inference engine (packages/cli-v3/CLAUDE.md)

Code in src/entryPoints/ runs inside customer containers and is a different runtime environment from the CLI - changes affect deployed task execution directly

Files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

For public packages, use build for verification.

Files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/vitest.config.ts
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
packages/trigger-sdk/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

In the Trigger.dev SDK (packages/trigger-sdk), prefer isomorphic code like fetch and ReadableStream instead of Node.js-specific code

Files:

  • packages/trigger-sdk/src/v3/chat.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
packages/trigger-sdk/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (packages/trigger-sdk/CLAUDE.md)

Always import from @trigger.dev/sdk. Never use @trigger.dev/sdk/v3 (deprecated path alias)

Files:

  • packages/trigger-sdk/src/v3/chat.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
packages/cli-v3/src/dev/**/*

📄 CodeRabbit inference engine (packages/cli-v3/CLAUDE.md)

Dev mode code should be located in src/dev/ and runs tasks locally in the user's Node.js process without containers

Files:

  • packages/cli-v3/src/dev/devSupervisor.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use vitest for all tests in the Trigger.dev repository

**/*.{test,spec}.{ts,tsx}: Use Vitest exclusively and never mock dependencies; use Testcontainers for integration dependencies.
Place test files next to the source files they test.

Files:

  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/slack/src/index.test.ts
**/package.json

📄 CodeRabbit inference engine (AGENTS.md)

When adding Zod, use the exact repository-wide pinned version 3.25.76, never a different version or range.

Files:

  • packages/slack/package.json
🧠 Learnings (21)
📚 Learning: 2026-03-10T12:44:14.176Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 3200
File: docs/config/config-file.mdx:353-368
Timestamp: 2026-03-10T12:44:14.176Z
Learning: In the trigger.dev repo, docs PRs are often companions to implementation PRs. When reviewing docs PRs (MDX files under docs/), check the PR description for any companion/related PR references and verify that the documented features exist in those companion PRs before flagging missing implementations. This ensures docs stay in sync with code changes across related PRs.

Applied to files:

  • docs/webhooks/connect.mdx
  • docs/webhooks/deliveries.mdx
  • docs/webhooks/human-in-the-loop.mdx
  • docs/webhooks/overview.mdx
  • docs/webhooks/filters.mdx
  • docs/ai-chat/reference.mdx
  • docs/webhooks/session-routing.mdx
  • docs/webhooks/channels.mdx
  • docs/webhooks/sources.mdx
  • docs/ai-chat/backend.mdx
📚 Learning: 2026-04-30T20:30:29.458Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3226
File: docs/ai-chat/quick-start.mdx:13-13
Timestamp: 2026-04-30T20:30:29.458Z
Learning: In this repo’s documentation MDX files (`docs/**/*.mdx`), use `ts` and `tsx` (not `typescript`) as the code-fence language tags for TypeScript/TSX snippets. Do not flag `ts`/`tsx` code-fence language tags as incorrect in any docs MDX file, since this is the site-wide Mintlify-compatible convention.

Applied to files:

  • docs/webhooks/connect.mdx
  • docs/webhooks/deliveries.mdx
  • docs/webhooks/human-in-the-loop.mdx
  • docs/webhooks/overview.mdx
  • docs/webhooks/filters.mdx
  • docs/ai-chat/reference.mdx
  • docs/webhooks/session-routing.mdx
  • docs/webhooks/channels.mdx
  • docs/webhooks/sources.mdx
  • docs/ai-chat/backend.mdx
📚 Learning: 2026-03-22T13:26:12.060Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/code/TextEditor.tsx:81-86
Timestamp: 2026-03-22T13:26:12.060Z
Learning: In the triggerdotdev/trigger.dev codebase, do not flag `navigator.clipboard.writeText(...)` calls for `missing-await`/`unhandled-promise` issues. These clipboard writes are intentionally invoked without `await` and without `catch` handlers across the project; keep that behavior consistent when reviewing TypeScript/TSX files (e.g., usages like in `apps/webapp/app/components/code/TextEditor.tsx`).

Applied to files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/vitest.config.ts
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-03-22T19:24:14.403Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3187
File: apps/webapp/app/v3/services/alerts/deliverErrorGroupAlert.server.ts:200-204
Timestamp: 2026-03-22T19:24:14.403Z
Learning: In the triggerdotdev/trigger.dev codebase, webhook URLs are not expected to contain embedded credentials/secrets (e.g., fields like `ProjectAlertWebhookProperties` should only hold credential-free webhook endpoints). During code review, if you see logging or inclusion of raw webhook URLs in error messages, do not automatically treat it as a credential-leak/secrets-in-logs issue by default—first verify the URL does not contain embedded credentials (for example, no username/password in the URL, no obvious secret/token query params or fragments). If the URL is credential-free per this project’s conventions, allow the logging.

Applied to files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/vitest.config.ts
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-05-18T08:21:27.694Z
Learnt from: d-cs
Repo: triggerdotdev/trigger.dev PR: 3632
File: apps/webapp/sentry.server.ts:4-21
Timestamp: 2026-05-18T08:21:27.694Z
Learning: When handling Prisma error P1001 ("Can't reach database server") in TypeScript, don’t assume a single error shape. Prisma can surface P1001 via two different error classes/fields: `PrismaClientKnownRequestError` exposes it as `err.code === "P1001"` (common during mid-query connection drops), while `PrismaClientInitializationError` exposes it as `err.errorCode === "P1001"` (common on client startup failure). Therefore, predicates should use `err.code === "P1001" || err.errorCode === "P1001"`. Do not flag `err.code === "P1001"` as “unreachable/never matches,” as it is expected in production.

Applied to files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/vitest.config.ts
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-05-18T08:21:27.694Z
Learnt from: d-cs
Repo: triggerdotdev/trigger.dev PR: 3632
File: apps/webapp/sentry.server.ts:4-21
Timestamp: 2026-05-18T08:21:27.694Z
Learning: When handling Prisma errors for P1001 ("Can't reach database server"), do not assume it only appears under a single property name. Prisma may surface P1001 via either `PrismaClientKnownRequestError` (`err.code === "P1001"`, e.g., mid-query connection drops) or `PrismaClientInitializationError` (`err.errorCode === "P1001"`, e.g., client startup connection failure). To reliably detect the condition, check `err.code === "P1001" || err.errorCode === "P1001"`, and avoid review rules that would incorrectly flag `err.code === "P1001"` as unreachable/never-matching.

Applied to files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/vitest.config.ts
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-06-13T19:53:13.759Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3937
File: packages/trigger-sdk/skills/realtime-and-frontend/SKILL.md:258-260
Timestamp: 2026-06-13T19:53:13.759Z
Learning: When reviewing code that uses `trigger.dev/react-hooks`’s `useRealtimeRun`, preserve the call signature where the first argument is the full realtime handle object (not `handle.id`). This is intentional to maintain type-safety and is consistent with the official docs; do not suggest changing the first argument from the handle object to `handle.id`.

Applied to files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/vitest.config.ts
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-06-17T17:13:49.929Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3948
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.bulk-actions.$bulkActionParam/route.tsx:48-62
Timestamp: 2026-06-17T17:13:49.929Z
Learning: In triggerdotdev/trigger.dev, within `dashboardLoader`/`dashboardAction` (or similar context resolver code) whenever you resolve an organization ID from an organization slug for RBAC/enterprise authorization scope, always read from the primary Prisma client (`prisma`), not `$replica`. Using `$replica` can hit replica-lag and cause the RBAC lookup/authorization to run without the correct org scope (bypassing intended role enforcement). Implement the slug→org lookup with `prisma.organization.findFirst(...)` (or equivalent primary-client query) and add an inline comment documenting why the primary client is required (replica lag could lead to unscoped RBAC checks).

Applied to files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/vitest.config.ts
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-06-23T13:04:21.413Z
Learnt from: carderne
Repo: triggerdotdev/trigger.dev PR: 4023
File: apps/webapp/app/services/upsertBranch.server.ts:14-18
Timestamp: 2026-06-23T13:04:21.413Z
Learning: In TypeScript, it’s valid to `import { type X }` and then use `typeof X` in a type-only position, e.g. `type Alias = z.infer<typeof X>`. The `type` modifier suppresses the runtime import, but the type checker still has the full exported type so `z.infer<typeof X>` can resolve correctly. In code reviews, don’t flag this as a TypeScript compile error as long as `typeof X` is used in a type context (e.g., with `z.infer`, `type` aliases, generics), not as a runtime value.

Applied to files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/vitest.config.ts
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-06-04T18:16:35.386Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 3836
File: apps/supervisor/src/backpressure/backpressureMonitor.ts:3-5
Timestamp: 2026-06-04T18:16:35.386Z
Learning: When reviewing TypeScript in this repo, apply the rule “prefer type aliases over interfaces” only to data/object shapes and union/intersection type modeling. If an interface is being used as a behavioral contract for collaborators to implement (e.g., method-shape interfaces that define required behavior, such as `BackpressureLogger` / `BackpressureSignalSource` in `apps/supervisor/src/backpressure/backpressureMonitor.ts`), keep it as an `interface` and do not flag it as a type-alias-vs-interface violation.

Applied to files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/vitest.config.ts
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-06-09T17:58:04.699Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 3879
File: apps/webapp/app/models/vercelIntegration.server.ts:619-630
Timestamp: 2026-06-09T17:58:04.699Z
Learning: In this codebase, outbound raw `fetch` calls should typically rely on Node/undici’s default request timeout (about ~300s) rather than adding a per-call `AbortController` + `setTimeout` wrapper inside individual functions (e.g. in files like `apps/webapp/app/models/vercelIntegration.server.ts`). During code review, do not flag the absence of a per-call timeout on a single `fetch` as an issue; if per-call timeouts are needed, they should be implemented via a codebase-wide convention (e.g., a shared fetch wrapper or documented pattern) rather than ad-hoc per-function changes.

Applied to files:

  • packages/cli-v3/src/entryPoints/dev-index-worker.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/cli-v3/src/dev/devSupervisor.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/cli-v3/src/entryPoints/managed-index-worker.ts
  • packages/slack/vitest.config.ts
  • packages/slack/src/index.test.ts
  • packages/slack/src/index.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-03-31T21:37:27.212Z
Learnt from: isshaddad
Repo: triggerdotdev/trigger.dev PR: 3283
File: docs/migration-n8n.mdx:19-21
Timestamp: 2026-03-31T21:37:27.212Z
Learning: When reviewing code in `packages/trigger-sdk/src/v3`, treat `tasks.triggerAndWait()` and `tasks.batchTriggerAndWait()` as real exported APIs. They are defined in `shared.ts` and re-exported via the `tasks` object in `tasks.ts`, and they take the task ID string as their first argument (not a task instance). This is distinct from the instance methods `yourTask.triggerAndWait()` and `yourTask.batchTriggerAndWait()`. Do not flag calls to `tasks.triggerAndWait()` or `tasks.batchTriggerAndWait()` as non-existent or incorrectly invoked.

Applied to files:

  • packages/trigger-sdk/src/v3/chat.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-05-17T08:08:12.370Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3644
File: packages/trigger-sdk/src/v3/ai.ts:8695-8746
Timestamp: 2026-05-17T08:08:12.370Z
Learning: In the Trigger v3 session resume/streams logic, ensure session resumption uses sequence cursors rather than timestamps. Specifically: for each turn-complete control record written to `session.out`, include a `session-in-event-id` header whose value is the committed-consume cursor (`session.in.lastDispatchedSeqNum`). On boot/resume, scan `session.out` for the latest turn-complete record, read the `session-in-event-id` header, and seed the `sessionStreams` manager for `.in` using both `lastSeqNum` and `lastDispatchedSeqNum` so previously processed user messages are not replayed. Do not use `setMinTimestamp`/`lastOutTimestamp` for resume ordering in this flow.

Applied to files:

  • packages/trigger-sdk/src/v3/chat.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-05-18T14:19:56.437Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3655
File: packages/trigger-sdk/src/v3/ai.ts:8667-8731
Timestamp: 2026-05-18T14:19:56.437Z
Learning: In the Trigger SDK (v3) when making raw `fetch` calls to the Trigger API (including override paths such as `createChatStartSessionAction`), set the request headers to match `ApiClient`: `Content-Type`, `Authorization`, and `x-trigger-source: "sdk"`. Also forward the current preview branch by setting `x-trigger-branch` to `apiClientManager.branchName`. Prefer using the shared `overrideRequestHeaders(accessToken)` helper instead of manually constructing headers, so requests route correctly to preview environments.

Applied to files:

  • packages/trigger-sdk/src/v3/chat.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-05-19T22:37:47.286Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3671
File: packages/trigger-sdk/test/recovery-boot.test.ts:456-457
Timestamp: 2026-05-19T22:37:47.286Z
Learning: In `packages/trigger-sdk` (Trigger.dev SDK), `logger.warn` (and other SDK logger methods) should route to the Trigger.dev structured logger sink, not to `console.warn`. In SDK tests, `vi.spyOn(console, "warn")` (or similar console spies) should only be used to suppress stray console output; reviewers should not suggest asserting on `console.warn` spies to verify SDK-internal warning/fallback log behavior. Use the SDK’s structured-logger outputs/capture approach instead of console spies.

Applied to files:

  • packages/trigger-sdk/src/v3/chat.ts
  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/trigger-sdk/src/v3/webhooks.ts
  • packages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-05-18T14:40:02.173Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3658
File: packages/core/src/v3/realtimeStreams/manager.test.ts:1-147
Timestamp: 2026-05-18T14:40:02.173Z
Learning: In this repo’s trigger.dev codebase, the “never mock — use testcontainers” guideline should only be applied to integration tests that talk to real external services (e.g., Redis, Postgres, S2). For unit tests that validate in-memory logic (e.g., deduplication/cache behavior in StandardRealtimeStreamsManager and similar module-boundary call counting), it is allowed to use Vitest mocks like `vi.fn()` and to stub/mock `ApiClient` objects to count calls or simulate in-process collaborators. Do not flag `vi.fn()`-based mocks as policy violations in these unit-test scenarios; reserve the rule for true external-service integration tests.

Applied to files:

  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/slack/src/index.test.ts
📚 Learning: 2026-05-18T14:40:02.173Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3658
File: packages/core/src/v3/realtimeStreams/manager.test.ts:1-147
Timestamp: 2026-05-18T14:40:02.173Z
Learning: In the triggerdotdev/trigger.dev repo, the policy “Never mock anything — use testcontainers instead” should only be enforced for integration tests that interact with real external services (e.g., Redis, Postgres) via actual infrastructure. For unit tests that exercise pure in-memory logic (e.g., cache semantics) it is OK to stub collaborators such as `ApiClient` using Vitest (`vi.fn()`) to assert call counts or control behavior. Do not flag `vi.fn()`-based `ApiClient` stubs in unit tests as violations of the testcontainers policy.

Applied to files:

  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/slack/src/index.test.ts
📚 Learning: 2026-06-16T09:19:47.637Z
Learnt from: d-cs
Repo: triggerdotdev/trigger.dev PR: 3960
File: apps/webapp/test/prismaInfrastructureErrorCapture.test.ts:0-0
Timestamp: 2026-06-16T09:19:47.637Z
Learning: In this repo’s Vitest setup, `vitest.config.ts` uses `globals: true`, so identifiers like `vi`, `describe`, `it`, and `expect` are available as globals in Vitest test files. During code review, do not flag missing `vi`/`describe`/`it`/`expect` imports as a runtime error or correctness issue when they’re used in `*.test.ts/tsx` or `*.spec.ts/tsx` files. Explicit imports are still preferred for consistency, but they’re not required for runtime behavior.

Applied to files:

  • packages/trigger-sdk/src/v3/channelReactions.test.ts
  • packages/slack/src/index.test.ts
📚 Learning: 2026-05-01T15:45:08.099Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3499
File: packages/plugins/tsup.config.ts:3-3
Timestamp: 2026-05-01T15:45:08.099Z
Learning: In build/tool configuration files (e.g., tsup.config.ts, vite.config.ts, vitest.config.ts), follow the tool’s documented export pattern and use `export default defineConfig(...)` (or the equivalent documented default export). The repo-wide guideline “use named exports instead of default exports” should apply only to application code (*.{ts,tsx,js,jsx}), not to these build/tool config files—so do not flag `export default defineConfig(...)` in these config files as a violation.

Applied to files:

  • packages/slack/vitest.config.ts
📚 Learning: 2026-06-16T13:14:09.440Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3964
File: docs/ai-chat/reference.mdx:482-482
Timestamp: 2026-06-16T13:14:09.440Z
Learning: When documenting or reviewing usage of `ChatTurn.complete(source?)` (in `packages/trigger-sdk/src/v3/ai.ts`), note that `source` is optional (`source?: UIMessageStreamable`). Calling `complete()` with no `source` is valid specifically for a final head-start handover (`handover.isFinal`), because the warm partial already contains the response. If examples or guidance omit `source`, ensure they are in this final-hand-over context so they remain correct.

Applied to files:

  • docs/ai-chat/reference.mdx
  • docs/ai-chat/backend.mdx
📚 Learning: 2026-06-16T13:14:14.382Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3964
File: docs/ai-chat/reference.mdx:478-478
Timestamp: 2026-06-16T13:14:14.382Z
Learning: When reviewing RC-gated `ai-chat` docs under `docs/ai-chat/`, don’t immediately flag missing SDK type fields or implementation details just because the field isn’t present on the docs branch yet. Instead, find and cross-check the companion implementation PR that’s intended to land alongside the docs PR, and only report missing/incorrect fields if they are also absent in the companion SDK/type changes.

Applied to files:

  • docs/ai-chat/reference.mdx
  • docs/ai-chat/backend.mdx
🪛 GitHub Actions: 📦 Preview packages (pkg.pr.new) / 0_Build and publish previews.txt
packages/trigger-sdk/src/v3/ai.ts

[error] 39-39: TypeScript build failed: Module '@trigger.dev/core/v3' has no exported member 'AnyChatEvent' (TS2305). Failed command: tshy.

🪛 GitHub Actions: 📦 Preview packages (pkg.pr.new) / Build and publish previews
packages/trigger-sdk/src/v3/ai.ts

[error] 39-39: TypeScript build failed in '@trigger.dev/sdk:build': Module '@trigger.dev/core/v3' has no exported member 'AnyChatEvent' (TS2305).

🪛 GitHub Check: code-quality / code-quality
packages/slack/src/index.test.ts

[warning] 97-97: eslint(no-unsafe-optional-chaining)
Unsafe usage of optional chaining


[warning] 48-48: eslint(no-unsafe-optional-chaining)
Unsafe usage of optional chaining

🪛 GitHub Check: CodeQL
packages/slack/src/index.ts

[failure] 306-307: Polynomial regular expression used on uncontrolled data
This regular expression that depends on library input may run slow on strings starting with '[' and with many repetitions of '[\'.
This regular expression that depends on library input may run slow on strings starting with '[\](http://' and with many repetitions of '[!](http://'.

packages/trigger-sdk/src/v3/webhooks.ts

[failure] 309-313: Polynomial regular expression used on uncontrolled data
This regular expression that depends on library input may run slow on strings starting with '{{' and with many repetitions of '{{|'.
This regular expression that depends on library input may run slow on strings starting with '{{' and with many repetitions of '{{|'.
This regular expression that depends on library input may run slow on strings starting with '{{' and with many repetitions of '{{|'.
This regular expression that depends on library input may run slow on strings starting with '{{' and with many repetitions of '{{|'.

🪛 LanguageTool
.changeset/hosted-webhook-ingress.md

[uncategorized] ~10-~10: The official name of this software platform is spelled with a capital “H”.
Context: ...rce with a preset (webhooks.stripe(), webhooks.github(), and others) or `webhooks.custom(...

(GITHUB)

docs/webhooks/sources.mdx

[uncategorized] ~53-~53: The official name of this software platform is spelled with a capital “H”.
Context: ... The available presets are stripe(), github(), svix(), square(), and `discord(...

(GITHUB)

🔇 Additional comments (36)
docs/webhooks/overview.mdx (1)

1-96: LGTM!

docs/webhooks/connect.mdx (1)

1-35: LGTM!

docs/webhooks/deliveries.mdx (1)

1-48: LGTM!

docs/webhooks/filters.mdx (1)

1-87: LGTM!

Also applies to: 97-99

docs/webhooks/session-routing.mdx (1)

1-96: LGTM!

docs/webhooks/channels.mdx (1)

20-28: LGTM!

Also applies to: 38-134

docs/webhooks/human-in-the-loop.mdx (1)

1-100: LGTM!

Also applies to: 121-143

docs/ai-chat/backend.mdx (1)

473-502: LGTM!

docs/ai-chat/reference.mdx (1)

50-51: LGTM!

Also applies to: 506-507, 537-572

docs/docs.json (1)

150-162: LGTM!

.changeset/hosted-webhook-ingress.md (1)

1-14: LGTM!

packages/cli-v3/src/dev/devSupervisor.ts (1)

35-35: LGTM!

packages/slack/src/index.ts (7)

39-83: LGTM!


125-133: LGTM!


141-189: LGTM!


237-247: LGTM!


286-297: LGTM!


328-333: LGTM!


377-392: LGTM!

packages/slack/tsconfig.json (1)

1-8: LGTM!

packages/slack/vitest.config.ts (1)

1-8: LGTM!

packages/slack/src/index.test.ts (1)

12-46: LGTM!

Also applies to: 115-248, 262-306

packages/slack/tsconfig.src.json (1)

5-11: 📐 Maintainability & Code Quality

No change needed for types: ["node"].

@types/node is available through the workspace dependency, and TypeScript type-only resolution does not require @types/node to be declared by each package that references it.

			> Likely an incorrect or invalid review comment.
packages/trigger-sdk/src/v3/webhooks.ts (4)

199-260: LGTM!


262-295: LGTM!


308-314: 🔒 Security & Privacy

The CodeQL ReDoS finding is a false positive at this call site.

[^}]+ is a negated class bounded by literal { and }. It has no ambiguous alternation, so the worst case is quadratic, not exponential, and only on input with many unclosed {.

The input is the key template that the developer writes in source and that runs once during indexing. It is not request data. Dismiss the alert or add a suppression comment so the check stops failing the pipeline.

Source: Linters/SAST tools


163-177: 🎯 Functional Correctness

No change needed.

gitlab can use the GitLab signing-token preset when configured, and whatsapp already matches the GitHub-style X-Hub-Signature-256 scheme.

packages/trigger-sdk/src/v3/ai.ts (7)

39-46: LGTM!

Also applies to: 61-61, 183-193


1266-1300: LGTM!


4840-4917: LGTM!

Also applies to: 4919-5047


5113-5132: LGTM!

Also applies to: 5235-5253, 5896-5920


6294-6297: LGTM!


8261-8315: LGTM!


8818-8863: LGTM!

Also applies to: 11399-11402, 11417-11418

packages/trigger-sdk/src/v3/chat.ts (1)

100-117: LGTM!

packages/trigger-sdk/src/v3/channelReactions.test.ts (1)

17-38: LGTM!

Comment thread docs/webhooks/channels.mdx
Comment thread docs/webhooks/sources.mdx
Comment thread packages/cli-v3/src/entryPoints/dev-index-worker.ts
Comment thread packages/slack/package.json
Comment thread packages/slack/src/index.test.ts Outdated
Comment thread packages/trigger-sdk/src/v3/ai.ts
Comment thread packages/trigger-sdk/src/v3/ai.ts
Comment thread packages/trigger-sdk/src/v3/ai.ts
Comment thread packages/trigger-sdk/src/v3/ai.ts
Comment thread packages/trigger-sdk/src/v3/webhooks.ts
@ericallam
ericallam force-pushed the feat/hosted-webhooks-api branch from b4b9f89 to 274c3ab Compare August 8, 2026 08:06
@ericallam
ericallam changed the base branch from main to feat/hosted-webhook-ingress August 8, 2026 08:06
@pkg-pr-new

pkg-pr-new Bot commented Aug 8, 2026

Copy link
Copy Markdown

Open in StackBlitz

@trigger.dev/build

npm i https://pkg.pr.new/triggerdotdev/trigger.dev/@trigger.dev/build@4b55ab5

trigger.dev

npm i https://pkg.pr.new/triggerdotdev/trigger.dev@4b55ab5

@trigger.dev/core

npm i https://pkg.pr.new/triggerdotdev/trigger.dev/@trigger.dev/core@4b55ab5

@trigger.dev/python

npm i https://pkg.pr.new/triggerdotdev/trigger.dev/@trigger.dev/python@4b55ab5

@trigger.dev/react-hooks

npm i https://pkg.pr.new/triggerdotdev/trigger.dev/@trigger.dev/react-hooks@4b55ab5

@trigger.dev/redis-worker

npm i https://pkg.pr.new/triggerdotdev/trigger.dev/@trigger.dev/redis-worker@4b55ab5

@trigger.dev/rsc

npm i https://pkg.pr.new/triggerdotdev/trigger.dev/@trigger.dev/rsc@4b55ab5

@trigger.dev/schema-to-json

npm i https://pkg.pr.new/triggerdotdev/trigger.dev/@trigger.dev/schema-to-json@4b55ab5

@trigger.dev/slack

npm i https://pkg.pr.new/triggerdotdev/trigger.dev/@trigger.dev/slack@4b55ab5

@trigger.dev/sdk

npm i https://pkg.pr.new/triggerdotdev/trigger.dev/@trigger.dev/sdk@4b55ab5

commit: 4b55ab5

@ericallam
ericallam force-pushed the feat/hosted-webhooks-api branch 8 times, most recently from 0430f92 to 481f6c1 Compare August 8, 2026 16:51
The deploy path now forwards declared webhooks to the server the same way dev does, so hosted webhook endpoints are created and stay active on deploy instead of only working under trigger dev.
Two webhook() declarations sharing an id used to silently overwrite each other in the worker manifest. Indexing now fails with the colliding ids and their file paths, matching how duplicate task ids are already handled.
The HITL approval block serialized the tool input without a bound into a Slack section text field, which is capped near 3000 characters. A large input made chat.postMessage fail with invalid_blocks so the approve and deny controls never appeared. The serialized input is now capped to keep the block within the limit.
…g a turn

A channel interaction callback (for example a Slack button click) that resolves to a tool call with no matching pending tool part is a stale or duplicate callback. It was falling through to the inbound-message path, which acked, reacted, and ran a full agent turn. Such callbacks are now dropped: no turn runs and the run returns to its idle wait for the next message.
@ericallam
ericallam force-pushed the feat/hosted-webhooks-api branch from 87c5f8b to d915b8f Compare August 8, 2026 19:42
The HITL renderer only posted approve/deny buttons for the first pending tool call, so when a turn paused on multiple tool approvals the rest never got controls and the turn could not finish. It now renders a section plus an approve/deny pair for each pending call.
…isting

The Slack package sets types: ["node"] in its tsconfig but did not declare @types/node, so type resolution depended on workspace hoisting. Declare it at the repo-pinned version, matching the other packages that opt into node types. vitest stays root-provided, consistent with every other package.
The channels setup listed only chat:write, which posts replies but does not grant read access to message.channels events. Add channels:history to the app scopes and note that adding scopes after install requires a reinstall.
…king

The link replacement in toSlackMrkdwn used unbounded character classes, which can backtrack quadratically on pathological input. Bound the link text and URL lengths and exclude newlines. Also tightened two test assertions that used unsafe optional chaining.
Several webhook doc code blocks used webhook, webhooks, streamText, anthropic, or chat without importing them, so a copied snippet would not type-check on its own. Add the imports to the standalone examples across sources, filters, channels, and human-in-the-loop.
Add channel-event delivery to the mockChatAgent harness (sendChannelEvent)
and a recordingChannelConnector helper to @trigger.dev/sdk/ai/test, so a
chat.agent's channel round-trip (inbound mapping, ack placeholder, egress
send, edit-in-place, and lifecycle reactions) can be driven and asserted
entirely offline.
Three fixes to chat.agent channel egress:

The debounced stream editor now re-arms after an edit it skipped because a
previous edit was still in flight, so text buffered during that window still
reaches the channel instead of stalling until the next delta.

The stream editor is stopped when the reply stream is aborted or cancelled,
not just on normal completion, so a late timer can no longer edit the channel
message after the turn has ended.

A turn that throws now edits the placeholder to show the error, so a channel
user sees the failure instead of a message stuck on the loading placeholder.
Add a fire-and-forget deliverChannelEvent to the harness and loop-level tests
for the channel interaction paths: a resolved interaction callback resumes the
pending tool and finalizes the controls, and a stale callback that matches no
pending tool is dropped without running a turn or posting anything.
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.

2 participants