Skip to content

Conversation

@myftija
Copy link
Member

@myftija myftija commented Nov 21, 2025

description to be added soon

@changeset-bot
Copy link

changeset-bot bot commented Nov 21, 2025

🦋 Changeset detected

Latest commit: f0cd177

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

This PR includes changesets to release 26 packages
Name Type
trigger.dev Patch
@trigger.dev/core Patch
d3-chat Patch
references-d3-openai-agents Patch
references-nextjs-realtime Patch
references-realtime-hooks-test Patch
references-realtime-streams Patch
references-telemetry Patch
@trigger.dev/build Patch
@trigger.dev/python Patch
@trigger.dev/redis-worker Patch
@trigger.dev/schema-to-json Patch
@trigger.dev/sdk Patch
@internal/cache Patch
@internal/clickhouse Patch
@internal/redis Patch
@internal/replication Patch
@internal/run-engine Patch
@internal/schedule-engine Patch
@internal/testcontainers Patch
@internal/tracing Patch
@internal/zod-worker Patch
@trigger.dev/react-hooks Patch
@trigger.dev/rsc Patch
@trigger.dev/database Patch
@trigger.dev/otlp-importer Patch

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
Copy link
Contributor

coderabbitai bot commented Nov 21, 2025

Walkthrough

Adds artifact upload support using S3 presigned-posts (new ARTIFACTS_* env vars, ArtifactsService, and a POST API route). Introduces S2-based deployment event streaming with Redis-backed token caching and new DeploymentService APIs for creating streams, appending events, and issuing access tokens. Extends deployment lifecycle flows (initialize, finalize, fail, timeout, index-failed) to emit events and to support native builds (enqueueing builds, returning eventStream). Adds CLI native-build-server features (context archiving, upload, streaming, --native-build-server/--detach/--plain options), plain-mode logging/spinners, and new core schemas for artifact endpoints, initialize-discriminated union, and deployment events.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

  • apps/webapp/app/v3/services/deployment.server.ts — heavy S2/Redis integration, many new public methods, data-shape changes, and error/caching semantics.
  • apps/webapp/app/v3/services/initializeDeployment.server.ts — native build branching, event stream creation, enqueue and cancellation/error handling.
  • apps/webapp/app/v3/services/artifacts.server.ts & apps/webapp/app/routes/api.v1.artifacts.ts — S3 presigned-post creation, credential/endpoint handling, size limits, and API error mapping.
  • packages/core/src/v3/schemas/api.ts — discriminated union for initialize request, new artifact and deployment event schemas affecting API contracts.
  • packages/cli-v3 (src/commands/deploy.ts, src/deploy/archiveContext.ts, src/build/buildWorker.ts, src/build/extensions.ts, src/utilities/windows.ts) — new CLI flows, archive creation, streaming parsers, spinner/plain-mode behavior and related public option changes.
  • Cross-cutting changes to finalize/fail/timeout/deploymentIndex files — ensure consistent event logging, non-fatal error handling, and select/include fields (project.externalRef/shortCode).
  • Dependency and package.json updates (apps/webapp, packages/cli-v3) — verify imported AWS/S2/streamstore packages match runtime use and build.
  • Areas to pay special attention to:
    • Correct handling of credentials/endpoints and error mapping in ArtifactsService (presigned post creation and size enforcement).
    • Concurrency and cache expiry semantics in Redis token caching and getEventStreamAccessToken.
    • Backward compatibility of InitializeDeploymentRequestBody/response shapes and CLI interactions (native vs non-native flows).
    • Robustness of archive creation (ignore rules, file selection) and CLI plain-mode logging/spinner substitutions.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete, containing only placeholder text 'description to be added soon' without any actual details about the changes, testing, or rationale. Replace placeholder text with comprehensive description covering: what was changed and why, testing performed, any deployment or configuration considerations, and any related issues being closed.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding native-build-server support to the deploy command, which aligns with the extensive deployment-related changes throughout the PR.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cli-deploy-with-native-builders

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 and usage tips.

@myftija myftija force-pushed the cli-deploy-with-native-builders branch from f55aad5 to cf46ed4 Compare November 21, 2025 19:27
@myftija myftija changed the title feat(deployments): --native-build-server supportfor the deploy command feat(deployments): --native-build-server support for the deploy command Nov 21, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/cli-v3/src/utilities/windows.ts (1)

89-99: Windows implementation ignores the options parameter; the suggested fix is incomplete.

The ballmerSpinner function doesn't accept options, and critically, on line 103 it's called without passing options while wrappedClackSpinner receives them. This creates inconsistent behavior where Windows users won't receive cancelMessage handling.

The suggested diff updates ballmerSpinner's signature but misses updating the call site on line 103. Both changes are needed:

-const ballmerSpinner = () => ({
+const ballmerSpinner = (options: { cancelMessage?: string } = {}) => ({
   start: (msg?: string): void => {
     log.step(msg ?? "");
   },
   stop: (msg?: string, code?: number): void => {
-    log.message(msg ?? "");
+    log.message(msg ?? options.cancelMessage ?? "");
   },
   message: (msg?: string): void => {
     log.message(msg ?? "");
   },
 });
 
-export const spinner = (options: { cancelMessage?: string } = {}) =>
-  isWindows ? ballmerSpinner() : wrappedClackSpinner(options);
+export const spinner = (options: { cancelMessage?: string } = {}) =>
+  isWindows ? ballmerSpinner(options) : wrappedClackSpinner(options);
packages/cli-v3/src/commands/deploy.ts (1)

195-201: The --dry-run flag is indeed ignored when --native-build-server is enabled

The control flow confirms the issue: when options.nativeBuildServer is true (lines 300–310), the function calls handleNativeBuildServerDeploy and returns immediately, bypassing the dry-run check at line 353. The handleNativeBuildServerDeploy function contains no dry-run logic whatsoever and unconditionally creates artifacts, uploads files, and calls initializeDeployment.

This creates a semantic mismatch where deploy --native-build-server --dry-run performs a real deployment instead of a dry-run, contradicting the documented behavior of --dry-run.

Suggested fixes remain valid:

  • Implement true native dry-run (prepare archive, show size/path, skip artifact upload and deployment init), or
  • Reject the combination explicitly with a clear error message
🧹 Nitpick comments (10)
apps/webapp/app/services/platform.v3.server.ts (1)

532-555: Consider adding input validation.

The enqueueBuild function accepts artifactKey and options without validation. Consider adding checks to ensure:

  • artifactKey is non-empty
  • deploymentId is in expected format
  • Optional parameters are valid when provided

This would provide early failure detection before calling the platform client.

apps/webapp/app/v3/services/deploymentIndexFailed.server.ts (1)

4-5: Failure event logging integration looks correct; consider tightening selection and log noise

The added environment.project include paired with DeploymentService.appendToEventLog(...) wires this failure path into the deployment event log correctly without affecting the main control flow. Using failedDeployment for the shortCode and the original deployment.environment.project for externalRef is sound.

Two minor refinements to consider:

  • You can select: { externalRef: true } instead of project: true in the include to avoid fetching unused columns on every index failure.
  • appendToEventLog returns an s2_is_disabled error when S2 is off; with .orTee this will be logged as an error on every failure. If S2-disabled is expected in some environments, you may want to downgrade that specific case to debug/info or use .orElse to swallow it while still logging unexpected failures.

Also applies to: 35-41, 77-90

apps/webapp/app/v3/services/finalizeDeployment.server.ts (1)

1-2: Finalization event logging is correctly integrated and non‑disruptive

The added DeploymentService usage to append a "finalized" -> "succeeded" event after marking the deployment as DEPLOYED is consistent with the other lifecycle paths. Using authenticatedEnv.project for the project scope and finalizedDeployment for the shortCode is correct, and .orTee keeps failures from affecting the main finalize flow.

As with other call sites, if you expect S2 to be disabled in some environments, you may eventually want to treat the "s2_is_disabled" error as non-error logging to avoid noisy logs, but the current behavior is safe.

Also applies to: 12-12, 81-93

apps/webapp/app/v3/services/initializeDeployment.server.ts (1)

14-16: Native build and event stream initialization flow looks solid; a couple of small hardening opportunities

The changes here nicely integrate native builds and S2 event streams:

  • Skipping createRemoteImageBuild when payload.initialStatus === "PENDING" or payload.isNativeBuild avoids unnecessary Depot builds.
  • The new initialStatus logic preserves existing behavior for non-native deployments while defaulting native builds to PENDING when the caller doesn’t override it.
  • Creating the S2 stream + access token up front and returning eventStream (or undefined on failure) gives the CLI an immediate handle for streaming logs without coupling it to S2 availability.
  • The native build path that calls enqueueBuild(...), logs failures, attempts cancellation, and then surfaces a generic error keeps the database state consistent even when platform enqueue fails.

Two small robustness tweaks you might consider:

  1. Enforce artifactKey for native builds at the service boundary

    Right now, a missing or empty payload.artifactKey for isNativeBuild === true will only surface as a “Failed to enqueue build” after a platform call and subsequent cancellation. Adding an explicit validation up front would yield a clearer, more actionable error:

    if (payload.isNativeBuild && !payload.artifactKey) {
      throw new ServiceValidationError("artifactKey is required for native builds");
    }
  2. Align the comment with actual initialStatus behavior

    The comment says “Native builds always start in the PENDING status”, but the code keeps an explicit payload.initialStatus if provided. Either tightening the code to always force PENDING when isNativeBuild is true, or rephrasing the comment (e.g. “Native builds default to PENDING when an initialStatus isn’t provided”) would avoid confusion for future readers.

Neither of these is blocking, but they’d make the behavior more predictable and easier to reason about.

Also applies to: 95-99, 141-177, 189-191, 223-256, 261-262

apps/webapp/app/v3/services/timeoutDeployment.server.ts (1)

11-22: Timed‑out deployment event logging looks good; consider guarding for missing project

Using the updated timedOutDeployment together with the deployment service to append a finalized "timed_out" event before enqueueing alerts keeps the timeout path consistent with the rest of the deployment event logging.

If there’s any chance of legacy rows without environment/project, you may want a quick guard like:

if (!deployment.environment?.project) {
  logger.error("Deployment missing environment.project, skipping event log append", {
    deploymentId: deployment.id,
  });
} else {
  await deploymentService
    .appendToEventLog(deployment.environment.project, timedOutDeployment, [/* … */])
    .orTee((error) => {
      logger.error("Failed to append timed out deployment event to event log", { error });
    });
}

to avoid a runtime throw preventing alerts from being enqueued.

Also applies to: 37-61

packages/cli-v3/src/deploy/archiveContext.ts (1)

51-63: Context archiving logic is solid; a couple of minor resilience/perf tweaks

The overall flow (default ignores + .gitignore → glob → ignore re‑filter) looks good and should behave as expected.

Two small, optional improvements:

  1. Graceful failure for unreadable .gitignore – instead of throwing, you could log and proceed without it so a bad .gitignore doesn’t block deployments.
  2. Avoid sync I/O in getArchiveSize – since you’re already async, using the async stat API keeps the event loop non‑blocking.

For example:

-import { readFile } from "node:fs/promises";
+import { readFile, stat } from "node:fs/promises";
@@
   const [error, content] = await tryCatch(readFile(gitignorePath, "utf-8"));
 
   if (error) {
-    throw new Error(`Failed to read .gitignore at ${gitignorePath}: ${error.message}`);
+    logger.debug("Failed to read .gitignore, continuing without it", {
+      gitignorePath,
+      error,
+    });
+    return "";
   }
@@
 export async function getArchiveSize(archivePath: string): Promise<number> {
-  const { statSync } = await import("node:fs");
-  return statSync(archivePath).size;
+  const stats = await stat(archivePath);
+  return stats.size;
 }

Also applies to: 151-154

apps/webapp/app/v3/services/artifacts.server.ts (1)

35-61: Remove or use the unused contentLength parameter in createPresignedPost

createPresignedPost takes a contentLength argument but never uses it; the only enforced limit is sizeLimit via the "content-length-range" condition. That’s slightly confusing for readers and callers.

If you don’t plan to enforce an exact size server‑side, I’d drop the parameter for now:

-  public createArtifact(
+  public createArtifact(
     type: "deployment_context",
     authenticatedEnv: AuthenticatedEnvironment,
     contentLength?: number
   ) {
@@
-    return this.createPresignedPost(key, limit, contentLength).map((result) => ({
+    return this.createPresignedPost(key, limit).map((result) => ({
@@
-  private createPresignedPost(key: string, sizeLimit: number, contentLength?: number) {
+  private createPresignedPost(key: string, sizeLimit: number) {

You can always reintroduce a contentLength constraint later if you decide to enforce it at the presign level.

Also applies to: 63-85

packages/cli-v3/src/commands/deploy.ts (1)

875-999: Native build streaming flow is nice; consider avoiding process.exit and ensure Node globals are available

The native path that uploads the context archive, then streams build logs/events from S2 into a taskLog gives a good UX and matches the new DeploymentEvent model.

Two optional considerations:

  1. Node runtime expectations – this helper relies on global fetch, FormData, Blob, AbortController, and TextDecoder. Make sure the CLI’s supported Node version range guarantees these are available, or document that requirement, otherwise some users may hit runtime ReferenceErrors.
  2. Process termination inside the helper – rather than calling process.exit(0) on success/non‑streaming paths, you could just return and let the surrounding command/telemetry wrapper decide when to exit. That tends to make the function easier to test and reuse.

The small DeploymentEventFromString helper at the bottom is a clean way to couple JSON parsing and schema validation before handling events.

Also applies to: 1001-1112, 1254-1264

apps/webapp/app/v3/services/deployment.server.ts (2)

307-423: S2 event helpers and token cache: good structure with minor reuse opportunities

The trio appendToEventLog / createEventStream / getEventStreamAccessToken is well‑structured:

  • Consistent stream naming (projects/${project.externalRef}/deployments/${deployment.shortCode}).
  • Early guard when S2 is disabled.
  • Token cache flow that gracefully falls back to issuing a new token and tolerates cache write failures while still returning a usable token.

Two minor maintainability tweaks you could consider:

  1. Factor out the stream name construction

You currently repeat the same pattern in multiple places (append, create, and implicitly in the token scope). Extracting a helper keeps these in sync:

+  private deploymentStreamName(
+    project: Pick<Project, "externalRef">,
+    deploymentShortCode: string
+  ) {
+    return `projects/${project.externalRef}/deployments/${deploymentShortCode}`;
+  }
+
   public appendToEventLog(
@@
-    const stream = basin.stream(
-      `projects/${project.externalRef}/deployments/${deployment.shortCode}`
-    );
+    const stream = basin.stream(
+      this.deploymentStreamName(project, deployment.shortCode)
+    );
@@
   public createEventStream(
@@
-        stream: `projects/${project.externalRef}/deployments/${deployment.shortCode}`,
+        stream: this.deploymentStreamName(project, deployment.shortCode),
@@
-            streams: {
-              prefix: `projects/${project.externalRef}/deployments/`,
-            },
+            streams: {
+              prefix: `projects/${project.externalRef}/deployments/`,
+            },

(You may also want a separate helper for the stream prefix if it ever diverges from the full name.)

  1. Optional: log cache read failures as well

Right now, any Redis get error is silently treated like a cache miss and only setex errors are logged. If you care about diagnosing cache health, you might want a lightweight log in the getTokenFromCache error mapper (still falling back to token issuance afterward).

These are nice‑to‑haves; the core behavior and error handling look solid.


436-445: Extended getDeployment select to include shortCode and project ref

Adding shortCode and environment.project.externalRef to the shared getDeployment selection is necessary for the new S2 event‑logging paths and keeps the lookup centralized.

The trade‑off is a slightly heavier query (extra join) for callers that only need id/status/imageReference, but that’s probably acceptable unless this path is very hot. If you see this becoming a perf hotspot, a follow‑up could split out a lighter‑weight helper for those simpler use cases.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8563ca and cf46ed4.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (23)
  • .changeset/config.json (1 hunks)
  • .changeset/proud-birds-change.md (1 hunks)
  • apps/webapp/app/env.server.ts (1 hunks)
  • apps/webapp/app/routes/api.v1.artifacts.ts (1 hunks)
  • apps/webapp/app/routes/api.v1.deployments.ts (2 hunks)
  • apps/webapp/app/services/platform.v3.server.ts (1 hunks)
  • apps/webapp/app/v3/services/artifacts.server.ts (1 hunks)
  • apps/webapp/app/v3/services/deployment.server.ts (8 hunks)
  • apps/webapp/app/v3/services/deploymentIndexFailed.server.ts (3 hunks)
  • apps/webapp/app/v3/services/failDeployment.server.ts (2 hunks)
  • apps/webapp/app/v3/services/finalizeDeployment.server.ts (3 hunks)
  • apps/webapp/app/v3/services/initializeDeployment.server.ts (5 hunks)
  • apps/webapp/app/v3/services/timeoutDeployment.server.ts (4 hunks)
  • apps/webapp/package.json (2 hunks)
  • internal-packages/database/prisma/schema.prisma (1 hunks)
  • packages/cli-v3/package.json (4 hunks)
  • packages/cli-v3/src/apiClient.ts (2 hunks)
  • packages/cli-v3/src/cli/common.ts (1 hunks)
  • packages/cli-v3/src/commands/deploy.ts (8 hunks)
  • packages/cli-v3/src/commands/workers/build.ts (1 hunks)
  • packages/cli-v3/src/deploy/archiveContext.ts (1 hunks)
  • packages/cli-v3/src/utilities/windows.ts (3 hunks)
  • packages/core/src/v3/schemas/api.ts (3 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2685
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings/route.tsx:1234-1257
Timestamp: 2025-11-14T19:24:39.536Z
Learning: In the trigger.dev project, version validation for the `useNativeBuildServer` setting cannot be performed at the settings form level because the SDK version is only known at build/deployment time, not when saving project settings.
📚 Learning: 2025-10-08T11:48:12.327Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2593
File: packages/core/src/v3/workers/warmStartClient.ts:168-170
Timestamp: 2025-10-08T11:48:12.327Z
Learning: The trigger.dev runners execute only in Node 21 and 22 environments, so modern Node.js APIs like AbortSignal.any (introduced in v20.3.0) are supported.

Applied to files:

  • apps/webapp/package.json
📚 Learning: 2025-11-14T19:24:39.536Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2685
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings/route.tsx:1234-1257
Timestamp: 2025-11-14T19:24:39.536Z
Learning: In the trigger.dev project, version validation for the `useNativeBuildServer` setting cannot be performed at the settings form level because the SDK version is only known at build/deployment time, not when saving project settings.

Applied to files:

  • .changeset/proud-birds-change.md
🧬 Code graph analysis (12)
apps/webapp/app/services/platform.v3.server.ts (1)
apps/webapp/app/v3/services/deployment.server.ts (1)
  • enqueueBuild (289-305)
apps/webapp/app/routes/api.v1.artifacts.ts (3)
apps/webapp/app/services/apiAuth.server.ts (1)
  • authenticateRequest (379-441)
packages/core/src/v3/schemas/api.ts (4)
  • CreateArtifactRequestBody (417-421)
  • CreateArtifactRequestBody (423-423)
  • CreateArtifactResponseBody (425-430)
  • CreateArtifactResponseBody (432-432)
apps/webapp/app/v3/services/artifacts.server.ts (1)
  • ArtifactsService (32-86)
apps/webapp/app/v3/services/failDeployment.server.ts (1)
apps/webapp/app/v3/services/deployment.server.ts (1)
  • DeploymentService (25-459)
packages/cli-v3/src/apiClient.ts (2)
packages/core/src/v3/schemas/api.ts (4)
  • CreateArtifactRequestBody (417-421)
  • CreateArtifactRequestBody (423-423)
  • CreateArtifactResponseBody (425-430)
  • CreateArtifactResponseBody (432-432)
packages/core/src/v3/apiClient/core.ts (1)
  • wrapZodFetch (727-767)
apps/webapp/app/v3/services/timeoutDeployment.server.ts (1)
apps/webapp/app/v3/services/deployment.server.ts (1)
  • DeploymentService (25-459)
apps/webapp/app/v3/services/artifacts.server.ts (1)
apps/webapp/app/env.server.ts (1)
  • env (1252-1252)
apps/webapp/app/v3/services/deploymentIndexFailed.server.ts (2)
apps/webapp/app/v3/services/deployment.server.ts (1)
  • DeploymentService (25-459)
apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts (1)
  • deployment (182-200)
apps/webapp/app/v3/services/initializeDeployment.server.ts (1)
apps/webapp/app/v3/services/deployment.server.ts (1)
  • DeploymentService (25-459)
packages/core/src/v3/schemas/api.ts (1)
packages/core/src/v3/schemas/common.ts (2)
  • GitMeta (239-253)
  • GitMeta (255-255)
apps/webapp/app/v3/services/finalizeDeployment.server.ts (1)
apps/webapp/app/v3/services/deployment.server.ts (1)
  • DeploymentService (25-459)
apps/webapp/app/v3/services/deployment.server.ts (3)
apps/webapp/app/env.server.ts (1)
  • env (1252-1252)
apps/webapp/app/services/platform.v3.server.ts (1)
  • enqueueBuild (532-555)
packages/core/src/v3/schemas/api.ts (2)
  • DeploymentEvent (600-603)
  • DeploymentEvent (605-605)
packages/cli-v3/src/commands/deploy.ts (8)
packages/core/src/v3/schemas/common.ts (2)
  • GitMeta (239-253)
  • GitMeta (255-255)
packages/cli-v3/src/utilities/windows.ts (1)
  • spinner (103-104)
packages/cli-v3/src/deploy/archiveContext.ts (2)
  • createContextArchive (91-149)
  • getArchiveSize (151-154)
packages/cli-v3/src/utilities/fileSystem.ts (1)
  • readFile (50-52)
packages/cli-v3/src/utilities/githubActions.ts (1)
  • setGithubActionsOutputAndEnvVars (3-27)
packages/cli-v3/src/utilities/cliOutput.ts (5)
  • isLinksSupported (7-7)
  • cliLink (140-145)
  • chalkGrey (20-22)
  • chalkWarning (28-30)
  • chalkError (24-26)
packages/core/src/v3/schemas/api.ts (4)
  • DeploymentFinalizedEvent (592-598)
  • DeploymentFinalizedEvent (607-607)
  • DeploymentEvent (600-603)
  • DeploymentEvent (605-605)
packages/cli-v3/src/cli/common.ts (1)
  • OutroCommandError (35-35)
🪛 Biome (2.1.2)
packages/cli-v3/src/commands/deploy.ts

[error] 1140-1164: This case is falling through to the next case.

Add a break or return statement to the end of this case to prevent fallthrough.

(lint/suspicious/noFallthroughSwitchClause)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (21)
packages/cli-v3/src/commands/workers/build.ts (1)

242-242: LGTM! Correct discriminator for traditional build path.

The addition of isNativeBuild: false appropriately identifies this as the traditional worker build workflow, distinguishing it from the new native build path being introduced in the PR.

packages/cli-v3/src/cli/common.ts (1)

68-73: OutroCommandError now exits with code 1 – confirm impact on callers

The added process.exit(1); brings OutroCommandError in line with BundleError, but it changes behavior: any command path that previously threw OutroCommandError will now terminate the process with a non‑zero exit code instead of behaving like a soft cancel. If any scripts/tools wrap these commands and treat “cancelled by user” as a success (exit code 0), this will be a breaking change.

If the intention is to treat cancellations as hard failures, this looks good. Otherwise, consider either:

  • Using process.exitCode = 1 (to keep behavior but allow outer handlers to decide), or
  • Leaving cancellation as a SkipCommandError path that does not force a non‑zero exit.
packages/cli-v3/src/utilities/windows.ts (2)

40-50: LGTM! Options properly forwarded to clackSpinner.

The signature update correctly accepts the options object and forwards it to the underlying clackSpinner. The implementation for non-Windows platforms is correct.


103-104: LGTM! Backward-compatible API enhancement.

The exported spinner function correctly accepts an optional options parameter with a sensible default, maintaining backward compatibility while enabling the new cancel message functionality. The platform-specific routing is correct.

internal-packages/database/prisma/schema.prisma (1)

1749-1749: LGTM! Whitespace formatting adjustment.

The additional whitespace aligns the field formatting with surrounding model fields without changing the schema definition.

packages/cli-v3/package.json (2)

95-95: LGTM! New dependencies align with PR objectives.

The added dependencies support the native build server features:

  • @s2-dev/streamstore: Enables S2-based event streaming for deployments
  • ignore: Supports .gitignore-style file filtering for deployment archives
  • tar: Required for creating deployment context archives

Also applies to: 116-116, 140-140


84-84: Verify that @clack/prompts 1.0.0-alpha.6 is compatible with your CLI usage.

Your update to 1.0.0-alpha.6 is confirmed as an alpha prerelease with potential for breaking API changes. Before adopting this version, ensure that:

  • The alpha version does not introduce breaking changes to the APIs your CLI depends on
  • Your current usage of @clack/prompts functions remains compatible
  • You are comfortable accepting ongoing instability until the stable v1.0.0 release
apps/webapp/package.json (2)

33-33: LGTM! AWS SDK additions support artifact storage.

The AWS SDK v3 modules are properly versioned and support the new S3-based artifact upload functionality.

Also applies to: 36-38


121-121: Verify prerelease platform version for production.

The @trigger.dev/platform dependency uses a prerelease version 0.0.0-prerelease-20251121183112. Ensure this version is stable and intended for production deployment, or plan to update to a stable release before merging.

apps/webapp/app/env.server.ts (1)

349-353: LGTM! Artifact storage configuration follows existing patterns.

The new ARTIFACTS_OBJECT_STORE_* environment variables mirror the existing OBJECT_STORE_* configuration pattern. Making BUCKET required while keeping credentials optional allows for flexible authentication methods (default credentials, IAM roles, etc.).

.changeset/proud-birds-change.md (1)

1-6: LGTM! Changeset clearly describes the feature.

The changeset appropriately documents the native build server support addition at the patch level.

apps/webapp/app/v3/services/failDeployment.server.ts (1)

54-67: LGTM! Proper integration of deployment event logging.

The deployment failure event is correctly appended to the S2 event log with appropriate error handling. The orTee pattern ensures that event logging failures don't interrupt the deployment failure workflow.

.changeset/config.json (1)

3-3: Configuration value is valid and standard.

The changelog generator "@changesets/cli/changelog" is the built-in/default changelog generator used by Changesets, so this is the correct standard configuration for your .changeset/config.json.

apps/webapp/app/routes/api.v1.deployments.ts (1)

40-52: eventStream propagation is consistent with the updated service and API schema

Wiring eventStream through from InitializeDeploymentService.call into the InitializeDeploymentResponseBody response looks consistent with the new initialization contract, and callers will simply see eventStream omitted/undefined when S2 is disabled or stream creation fails.

packages/cli-v3/src/apiClient.ts (1)

3-4: CLI artifact client method aligns with existing patterns

createArtifact mirrors the other client methods well: it validates accessToken, reuses getHeaders() (including branch), targets /api/v1/artifacts, and wraps the response with CreateArtifactResponseBody via wrapZodFetch. This should plug cleanly into the new artifact flow.

Also applies to: 365-375

packages/core/src/v3/schemas/api.ts (1)

417-432: New artifact and deployment event schemas look consistent with the native build flow

The added schemas for artifacts (CreateArtifact*), the extended InitializeDeployment* (with the isNativeBuild discriminator and optional native‑build fields), and the DeploymentEvent union (log + finalized with an open‑ended result) line up well with the new artifact + streaming behavior in the CLI and services. I don’t see issues with these API shapes from a compatibility or expressiveness standpoint.

Also applies to: 434-487, 582-607

packages/cli-v3/src/commands/deploy.ts (1)

62-82: Native build server flag wiring and branching look correct

The new nativeBuildServer flag is plumbed through Zod and commander, and the early branch to handleNativeBuildServerDeploy keeps the existing build/deploy path intact for users who don’t opt in. Explicitly sending isNativeBuild: false on the non‑native path also fits the updated schema and makes the behavior of older CLIs clearer on the server side.

Also applies to: 174-179, 300-310, 358-367

apps/webapp/app/v3/services/deployment.server.ts (4)

3-5: Module‑level S2 and Redis wiring looks consistent

The new neverthrow imports plus S2 client and Redis cache initialization are straightforward and match existing env/Redis patterns in the app. Centralizing these at module scope for reuse is reasonable; no issues from my side here.

Also applies to: 10-12, 14-23


126-135: Using getDeployment in progressDeployment improves consistency

Switching progressDeployment to go through the shared getDeployment helper (instead of inlining a Prisma query) is a nice cleanup and keeps selection/lookup logic centralized. The control flow and timeout extension behavior remain unchanged.


152-156: Cancellation + finalization event logging behavior and log level

The enriched types (shortCode + environment.project.externalRef) and the new “finalized/canceled” event append make sense, and I like that any S2 failures are tolerated so cancellation still completes.

One thing to consider: in environments where S2 is intentionally disabled, appendToEventLog will fail with s2_is_disabled, and the .orElse will log this as an error on every cancellation. That can get noisy and misleading when S2 is off by design. You might want to downgrade this to logger.debug/logger.info or branch on the error type:

-          .orElse((error) => {
-            logger.error("Failed to append event to deployment event log", { error });
-            return okAsync(deployment);
-          })
+          .orElse((error) => {
+            const level =
+              error.type === "s2_is_disabled" ? "info" : "error";
+            logger[level]("Failed to append event to deployment event log", { error });
+            return okAsync(deployment);
+          })

[ suggest_optional_refactor ]

Also applies to: 167-171, 194-195, 203-221


289-305: Clarify semantics when platform enqueueBuild is unavailable

This wrapper cleanly maps platform errors into a failed_to_enqueue_build result, which is good. However, the underlying platform.v3.enqueueBuild returns undefined (without throwing) when client is not configured, which this wrapper currently treats as a successful Ok(undefined).

If this method is used in contexts where a remote build is required (e.g. --native-build-server in cloud), consider treating a falsy result as an error so we don’t silently no‑op:

   return fromPromise(
-    enqueueBuild(authenticatedEnv.projectId, deployment.friendlyId, artifactKey, options),
-    (error) => ({
+    enqueueBuild(authenticatedEnv.projectId, deployment.friendlyId, artifactKey, options),
+    (error) => ({
       type: "failed_to_enqueue_build" as const,
       cause: error,
     })
-  );
+  ).andThen((result) => {
+    if (!result) {
+      return errAsync({ type: "failed_to_enqueue_build" as const, cause: "no_client" });
+    }
+    return okAsync(undefined);
+  });

If the current “no client == benign no‑op” behavior is intentional for self‑hosted setups, it’d be good to document that expectation at the call sites.
[ suggest_recommended_refactor ]

@myftija myftija force-pushed the cli-deploy-with-native-builders branch from cf46ed4 to 91358c5 Compare November 24, 2025 15:28
Spent a lot of time on it, but could not get it to work reliably. It clears lines that it should not clear when maininging the compact n-lines view during the log stream. Replaced it with a normal log instead for now.
@myftija myftija force-pushed the cli-deploy-with-native-builders branch from 91358c5 to 81f63ba Compare November 24, 2025 15:31
Avoid confusion with self-hosters.
"@trigger.dev/database": "workspace:*",
"@trigger.dev/otlp-importer": "workspace:*",
"@trigger.dev/platform": "1.0.20",
"@trigger.dev/platform": "0.0.0-prerelease-20251121183112",
Copy link
Member Author

Choose a reason for hiding this comment

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

update to the actual release before merging

@@ -1,11 +1,6 @@
{
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
"changelog": [
Copy link
Member Author

Choose a reason for hiding this comment

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

remove

@@ -0,0 +1,6 @@
---
"trigger.dev": patch
Copy link
Member Author

Choose a reason for hiding this comment

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

could also be a minor version bump

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/cli-v3/src/commands/deploy.ts (1)

62-83: --dry-run is ignored for --native-build-server, which breaks the documented contract

When options.nativeBuildServer is true, _deployCommand routes into handleNativeBuildServerDeploy and never reaches the existing options.dryRun check (Lines 360–363). In the native path, handleNativeBuildServerDeploy always creates an artifact, uploads it, initializes the deployment, and enqueues the build; there is no special handling for dryRun.

That means running:

trigger.dev deploy --native-build-server --dry-run

will still create and start a real deployment, which contradicts the current description of --dry-run (“This will not actually deploy the project”).

I’d recommend either:

  • Short‑term: explicitly reject this combination up-front, e.g.:
async function _deployCommand(dir: string, options: DeployCommandOptions) {
+ if (options.nativeBuildServer && options.dryRun) {
+   throw new Error("The --dry-run option is not supported with --native-build-server yet.");
+ }
  • Or, longer‑term: add dryRun handling into handleNativeBuildServerDeploy so that it only builds the local archive (and maybe logs its path/size) without creating the artifact, calling initializeDeployment, or streaming events.

Also applies to: 175-186, 203-205, 307-317, 360-363, 867-1007

♻️ Duplicate comments (1)
apps/webapp/app/routes/api.v1.artifacts.ts (1)

27-32: Handle JSON parse failures explicitly instead of defaulting to {}

Right now:

const [, rawBody] = await tryCatch(request.json());
const body = CreateArtifactRequestBody.safeParse(rawBody ?? {});

If request.json() throws (malformed JSON, wrong content type, empty body), rawBody ends up undefined, safeParse({}) may still succeed due to schema defaults, and you’ll create an artifact for an invalid request instead of returning a 4xx.

Consider short‑circuiting on JSON parse errors and only running the schema validation when parsing succeeds, e.g.:

-  const [, rawBody] = await tryCatch(request.json());
-  const body = CreateArtifactRequestBody.safeParse(rawBody ?? {});
+  const [bodyError, rawBody] = await tryCatch(request.json());
+
+  if (bodyError) {
+    logger.warn("Invalid JSON in artifact request body", {
+      url: request.url,
+      error: bodyError.message ?? String(bodyError),
+    });
+    return json({ error: "Invalid JSON body" }, { status: 400 });
+  }
+
+  const body = CreateArtifactRequestBody.safeParse(rawBody ?? {});

Also, please double‑check that tryCatch is actually exported from @trigger.dev/core/v3 for the version you’re using—other parts of the codebase typically import it from @trigger.dev/core or related utils, so aligning this import may avoid surprises.

#!/bin/bash
# Verify tryCatch import patterns and availability

# See how tryCatch is imported elsewhere for consistency
rg "import.*tryCatch" -n

# Confirm the resolved d.ts for @trigger.dev/core/v3 (path may vary)
fd "core.*.d.ts" node_modules | head
🧹 Nitpick comments (7)
packages/cli-v3/src/cli/common.ts (1)

68-82: Consider using process.exitCode = 1 instead of hard process.exit(1) in wrapper

Calling process.exit(1) inside wrapCommandAction makes this helper much harder to reuse or unit-test (any caller that doesn’t stub process.exit will have the process terminated), and the subsequent throw e becomes effectively dead in real CLI runs. Consider mirroring handleTelemetry and just setting process.exitCode = 1, leaving actual process termination to the top-level entrypoint/Commander.

packages/cli-v3/src/utilities/windows.ts (1)

40-51: Spinner options propagation looks good; you may want a reusable options type

Passing an options object through to clackSpinner is a nice improvement and the default {} keeps this backward compatible for existing spinner() call sites. If you expect to support more spinner options later, consider defining a shared SpinnerOptions type (and using it for both wrappedClackSpinner and spinner) that can be expanded without having to touch all call sites again.

Also applies to: 103-104

packages/core/src/v3/schemas/api.ts (2)

455-487: InitializeDeploymentRequestBody native-build union is well-shaped; consider clarifying docs

The intersection of the existing base object with a discriminated union on isNativeBuild (defaulting to false via preprocess) gives you:

  • Backwards compatibility for legacy callers that don’t send isNativeBuild at all (they land in the isNativeBuild: false branch).
  • A stricter native-build variant that requires skipPromotion and artifactKey, with optional configFilePath.

This is a solid way to evolve the API. I’d just suggest adding a brief JSDoc comment explaining that isNativeBuild defaults to false when missing so future readers don’t accidentally remove the preprocess and break old CLIs.


582-607: Deployment event schemas look good; anyString helper could be simplified

The DeploymentLogEvent / DeploymentFinalizedEvent / DeploymentEvent discriminated union is a clean way to model deployment log vs finalization events, and the optional+defaulted level on log events is a nice touch. The anyString custom schema for result is functionally equivalent to just allowing any string, though, so:

result: z.enum(["succeeded", "failed", "timed_out", "canceled"]).or(z.string())

would be simpler and convey the same runtime behavior and effective type.

apps/webapp/app/v3/services/initializeDeployment.server.ts (1)

14-15: Native-build initialization & S2 event stream integration look solid; consider exposing enqueue error detail

  • Skipping externalBuildData when initialStatus === "PENDING" or payload.isNativeBuild and computing initialStatus as payload.initialStatus ?? (payload.isNativeBuild ? "PENDING" : "BUILDING") preserves existing behavior while cleanly separating native builds into a queued state.
  • Creating the S2 event stream + access token via DeploymentService and treating any failure as non-fatal (logging and returning eventStream: undefined) aligns well with S2 being optional; non-S2 environments will still proceed with deployments. Based on learnings, this matches the “S2 may be disabled” constraint.
  • The native-build path that enqueues a build and cancels the deployment on failure is robust, and the neverthrow chaining correctly preserves the original enqueue error even if cancellation itself fails.

If you want more actionable feedback to callers when enqueue fails, consider throwing with some of the structured error details (e.g., error.type and/or a human-readable message) instead of a generic Error("Failed to enqueue build"), while still keeping the full cause in logs.

Also applies to: 95-98, 141-177, 189-191, 223-256, 258-262

apps/webapp/app/v3/services/artifacts.server.ts (1)

1-92: ArtifactsService is well-structured; minor refinements for size check and expiresAt shape

The presigned-post flow and key layout look good, with sensible size limits and error handling. Two small tweaks you might consider:

  1. Avoid truthy check on contentLength
    Using a truthy check will skip validation for contentLength = 0. It’s not wrong, but a more explicit check is clearer and future-proof:
-    if (contentLength && contentLength > limit) {
+    if (contentLength !== undefined && contentLength > limit) {
       return errAsync({
         type: "artifact_size_exceeds_limit" as const,
         contentLength,
         sizeLimit: limit,
       });
     }
  1. Align expiresAt with the public schema (string vs Date)
    CreateArtifactResponseBody expects expiresAt as an ISO string; you currently attach a Date and rely on JSON serialization at the route layer. Making it a string here avoids surprises for internal consumers before serialization:
    ).map((result) => ({
      ...result,
-      expiresAt,
+      expiresAt: expiresAt.toISOString(),
    }));

Neither change is strictly required for correctness with the current route, but they make the service’s contract clearer.

apps/webapp/app/v3/services/deployment.server.ts (1)

3-24: DeploymentService S2 integration and enqueueBuild helper look correct; consider richer logging context

  • Centralizing deployment lookups via getDeployment and reusing it in progressDeployment and cancelDeployment is a nice cleanup, and the added shortCode + environment.project.externalRef fields enable S2 integration without extra queries.
  • enqueueBuild wraps the platform enqueue call in a neverthrow ResultAsync, giving InitializeDeployment a clean way to distinguish enqueue failures from other errors.
  • The S2 helpers (appendToEventLog, createEventStream, getEventStreamAccessToken) are all gated on env.S2_ENABLED === "1" and the presence of the shared s2 client. When S2 is disabled, they short-circuit with a typed s2_is_disabled error, and callers like cancelDeployment explicitly treat those as non-fatal—this aligns with the requirement that S2 remains optional in some environments.
  • Token caching is sensibly defensive: cache read miss triggers token issuance, and cache write failures are logged but ignored, so log streaming can still proceed.

One small improvement: when appendToEventLog fails in the cancelDeployment chain, the log currently only includes the error object. Including basic identifiers like projectExternalRef and deployment.shortCode would make operational debugging easier, for example:

logger.error("Failed to append event to deployment event log", {
  error,
  projectExternalRef: deployment.environment.project.externalRef,
  shortCode: deployment.shortCode,
});

Also applies to: 126-136, 147-224, 289-305, 307-423, 425-458

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cf46ed4 and 6337613.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (24)
  • .changeset/config.json (1 hunks)
  • .changeset/proud-birds-change.md (1 hunks)
  • apps/webapp/app/env.server.ts (1 hunks)
  • apps/webapp/app/routes/api.v1.artifacts.ts (1 hunks)
  • apps/webapp/app/routes/api.v1.deployments.ts (2 hunks)
  • apps/webapp/app/services/platform.v3.server.ts (1 hunks)
  • apps/webapp/app/v3/services/artifacts.server.ts (1 hunks)
  • apps/webapp/app/v3/services/deployment.server.ts (8 hunks)
  • apps/webapp/app/v3/services/deploymentIndexFailed.server.ts (3 hunks)
  • apps/webapp/app/v3/services/failDeployment.server.ts (2 hunks)
  • apps/webapp/app/v3/services/finalizeDeployment.server.ts (3 hunks)
  • apps/webapp/app/v3/services/initializeDeployment.server.ts (5 hunks)
  • apps/webapp/app/v3/services/timeoutDeployment.server.ts (4 hunks)
  • apps/webapp/package.json (2 hunks)
  • internal-packages/database/prisma/schema.prisma (1 hunks)
  • packages/cli-v3/package.json (4 hunks)
  • packages/cli-v3/src/apiClient.ts (2 hunks)
  • packages/cli-v3/src/cli/common.ts (1 hunks)
  • packages/cli-v3/src/commands/deploy.ts (8 hunks)
  • packages/cli-v3/src/commands/workers/build.ts (1 hunks)
  • packages/cli-v3/src/deploy/archiveContext.ts (1 hunks)
  • packages/cli-v3/src/deploy/buildImage.ts (1 hunks)
  • packages/cli-v3/src/utilities/windows.ts (3 hunks)
  • packages/core/src/v3/schemas/api.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • packages/cli-v3/src/commands/workers/build.ts
  • packages/cli-v3/src/deploy/archiveContext.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/package.json
  • .changeset/config.json
  • apps/webapp/app/services/platform.v3.server.ts
  • internal-packages/database/prisma/schema.prisma
  • packages/cli-v3/package.json
  • .changeset/proud-birds-change.md
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2685
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings/route.tsx:1234-1257
Timestamp: 2025-11-14T19:24:39.536Z
Learning: In the trigger.dev project, version validation for the `useNativeBuildServer` setting cannot be performed at the settings form level because the SDK version is only known at build/deployment time, not when saving project settings.
📚 Learning: 2024-10-22T10:50:41.311Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 1424
File: packages/core/src/v3/errors.ts:155-189
Timestamp: 2024-10-22T10:50:41.311Z
Learning: When using `assertExhaustive` in a `switch` statement in TypeScript (e.g., in the `shouldRetryError` function in `packages/core/src/v3/errors.ts`), and it throws an error, it's acceptable not to add a `return` statement afterward, as control flow will not proceed beyond the `assertExhaustive` call.

Applied to files:

  • packages/cli-v3/src/commands/deploy.ts
📚 Learning: 2025-11-10T09:09:07.399Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2663
File: apps/webapp/app/env.server.ts:1205-1206
Timestamp: 2025-11-10T09:09:07.399Z
Learning: In the trigger.dev webapp, S2_ACCESS_TOKEN and S2_DEPLOYMENT_LOGS_BASIN_NAME environment variables must remain optional until an OSS version of S2 is available, to avoid breaking environments that don't have S2 provisioned.

Applied to files:

  • apps/webapp/app/v3/services/deployment.server.ts
🧬 Code graph analysis (6)
apps/webapp/app/v3/services/initializeDeployment.server.ts (2)
apps/webapp/app/v3/services/deployment.server.ts (1)
  • DeploymentService (25-459)
packages/core/src/v3/workers/taskExecutor.ts (1)
  • result (1285-1332)
packages/core/src/v3/schemas/api.ts (1)
packages/core/src/v3/schemas/common.ts (2)
  • GitMeta (239-253)
  • GitMeta (255-255)
apps/webapp/app/v3/services/failDeployment.server.ts (1)
apps/webapp/app/v3/services/deployment.server.ts (1)
  • DeploymentService (25-459)
packages/cli-v3/src/commands/deploy.ts (6)
packages/core/src/v3/schemas/common.ts (2)
  • GitMeta (239-253)
  • GitMeta (255-255)
packages/cli-v3/src/deploy/archiveContext.ts (2)
  • createContextArchive (91-149)
  • getArchiveSize (151-154)
packages/cli-v3/src/mcp/logger.ts (1)
  • log (14-23)
packages/cli-v3/src/utilities/cliOutput.ts (5)
  • chalkError (24-26)
  • isLinksSupported (7-7)
  • cliLink (140-145)
  • chalkGrey (20-22)
  • chalkWarning (28-30)
packages/cli-v3/src/utilities/githubActions.ts (1)
  • setGithubActionsOutputAndEnvVars (3-27)
packages/core/src/v3/schemas/api.ts (4)
  • DeploymentFinalizedEvent (592-598)
  • DeploymentFinalizedEvent (607-607)
  • DeploymentEvent (600-603)
  • DeploymentEvent (605-605)
apps/webapp/app/v3/services/deployment.server.ts (4)
apps/webapp/app/env.server.ts (1)
  • env (1252-1252)
apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts (1)
  • deployment (182-200)
apps/webapp/app/services/platform.v3.server.ts (1)
  • enqueueBuild (594-617)
packages/core/src/v3/schemas/api.ts (2)
  • DeploymentEvent (600-603)
  • DeploymentEvent (605-605)
packages/cli-v3/src/apiClient.ts (2)
packages/core/src/v3/schemas/api.ts (4)
  • CreateArtifactRequestBody (417-421)
  • CreateArtifactRequestBody (423-423)
  • CreateArtifactResponseBody (425-430)
  • CreateArtifactResponseBody (432-432)
packages/core/src/v3/apiClient/core.ts (1)
  • wrapZodFetch (727-767)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: typecheck / typecheck
🔇 Additional comments (10)
packages/cli-v3/src/deploy/buildImage.ts (1)

459-488: Registry login success message change is safe

Switching the user-facing log to “Successfully logged in to the remote registry” keeps sensitive details out of onLog while the debug logger still includes the concrete host. No behavioral or correctness concerns here.

packages/core/src/v3/schemas/api.ts (2)

417-432: Artifact request/response schemas look consistent with presigned-post flows

The CreateArtifactRequestBody/CreateArtifactResponseBody shapes look sane and align with a deployment-context artifact + S3-style presigned POST (key, URL, arbitrary string fields, and an expiry). If you know contentLength must be non‑negative and integral, you could tighten it to .int().nonnegative(), but that’s purely a validation hardening choice.


434-451: InitializeDeploymentResponseBody eventStream extension seems backward compatible

Adding the optional eventStream.s2.{basin,stream,accessToken} block keeps the existing response fields intact while allowing callers to opt into streaming when present. Clients that don’t know about eventStream will continue to work unchanged, and consumers that do can branch on its presence.

apps/webapp/app/v3/services/failDeployment.server.ts (1)

7-8: Appending a finalized “failed” deployment event is a solid addition

Creating a DeploymentService instance and appending a single "finalized" event with result: "failed" and the error message cleanly ties the fail path into the new deployment event log. Using .orTee to log but not throw keeps failure to write the event from breaking the primary failure flow, which feels like the right trade-off here.

Also applies to: 54-67

apps/webapp/app/v3/services/timeoutDeployment.server.ts (1)

16-21: Timed‑out update + event logging flow looks consistent

Including environment.project on the initial fetch and then logging a "finalized" "timed_out" event via DeploymentService before enqueueing alerts is coherent with the other deployment flows; the best‑effort .orTee logging keeps the main timeout path resilient. No further changes needed here.

Also applies to: 37-61

apps/webapp/app/routes/api.v1.deployments.ts (1)

40-52: Passing through eventStream aligns with the new response schema

Destructuring eventStream from InitializeDeploymentService.call and including it in the InitializeDeploymentResponseBody keeps this route aligned with the updated v3 API; the rest of the payload is unchanged and remains backward compatible for consumers that ignore the new field.

apps/webapp/app/v3/services/deploymentIndexFailed.server.ts (1)

4-12: Failure finalization + event logging is wired correctly

Typing FINAL_DEPLOYMENT_STATUSES with WorkerDeploymentStatus and fetching environment.project up front, then logging a "finalized" "failed" event via DeploymentService before enqueueing alerts, is consistent with the other deployment flows and keeps failure handling centralized. Looks good.

Also applies to: 35-42, 77-90

apps/webapp/app/v3/services/finalizeDeployment.server.ts (1)

1-3: Finalize flow’s event logging is consistent with other deployment outcomes

Using type‑only imports and delegating the "finalized" "succeeded" event to DeploymentService.appendToEventLog, with best‑effort .orTee error logging, keeps the finalize path aligned with the failure/timeout flows while not impacting promotion, engine scheduling, or alerts if logging fails. Looks good.

Also applies to: 12-12, 81-93

packages/cli-v3/src/apiClient.ts (1)

3-4: Artifact creation API wiring matches existing client patterns

The createArtifact helper reuses wrapZodFetch and getHeaders() consistently with the rest of CliApiClient, and the access-token guard mirrors other authenticated methods. Looks good to me.

Also applies to: 365-375

packages/cli-v3/src/commands/deploy.ts (1)

1019-1242: Native build log streaming and event parsing are robust and backward-compatible

The S2-based event streaming loop and DeploymentEventFromString helper look well thought out:

  • Errors creating the read session are handled gracefully: user is told to inspect the dashboard, and the command exits successfully instead of hanging.
  • The for await loop:
    • Skips malformed JSON with a debug log only.
    • Treats only known type values (log and finalized), with a default branch that asserts exhaustiveness and logs unknown types without breaking.
  • finalDeploymentEvent is required before proceeding; all the fallback branches (no events, only logs, or mid-stream disconnect) surface clear messages and throw OutroCommandError so the outer command can render a single coherent outro.
  • The result switch cleanly distinguishes succeeded, failed, timed_out, and canceled, and the success/default cases now use return process.exit(0);, which avoids the previous fallthrough issue while keeping the explicit exit codes.

Overall this gives users a good streaming UX while degrading nicely when the stream or event shape isn’t as expected.

Also applies to: 1262-1272

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/cli-v3/src/commands/deploy.ts (3)

978-978: Consider using a named constant for the placeholder contentHash.

The magic string "-" is used as a placeholder for native builds. While functional, extracting this to a named constant (e.g., NATIVE_BUILD_CONTENT_HASH_PLACEHOLDER) would improve code clarity.


1031-1072: Consider consistent process exit patterns.

Lines 1038 and 1071 use process.exit(0) without an explicit return, while the switch statement at lines 1190 and 1258 uses return process.exit(0). For consistency with the rest of the file, consider adding return before process.exit(0) calls.


889-1261: Consider extracting logical sections into helper functions.

The handleNativeBuildServerDeploy function spans 372 lines and handles multiple concerns: archiving, uploading, event streaming, and result processing. While the current implementation is correct and readable, extracting sections like artifact upload (lines 904-971), event streaming (lines 1031-1133), and result handling (lines 1166-1260) into focused helper functions would improve maintainability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6337613 and ba49783.

⛔ Files ignored due to path filters (2)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • references/hello-world/trigger.config.ts is excluded by !references/**
📒 Files selected for processing (5)
  • packages/cli-v3/package.json (3 hunks)
  • packages/cli-v3/src/build/buildWorker.ts (3 hunks)
  • packages/cli-v3/src/build/extensions.ts (4 hunks)
  • packages/cli-v3/src/commands/deploy.ts (17 hunks)
  • packages/cli-v3/src/utilities/windows.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli-v3/src/utilities/windows.ts
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2685
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings/route.tsx:1234-1257
Timestamp: 2025-11-14T19:24:39.536Z
Learning: In the trigger.dev project, version validation for the `useNativeBuildServer` setting cannot be performed at the settings form level because the SDK version is only known at build/deployment time, not when saving project settings.
📚 Learning: 2025-10-08T11:48:12.327Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2593
File: packages/core/src/v3/workers/warmStartClient.ts:168-170
Timestamp: 2025-10-08T11:48:12.327Z
Learning: The trigger.dev runners execute only in Node 21 and 22 environments, so modern Node.js APIs like AbortSignal.any (introduced in v20.3.0) are supported.

Applied to files:

  • packages/cli-v3/package.json
📚 Learning: 2024-10-22T10:50:41.311Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 1424
File: packages/core/src/v3/errors.ts:155-189
Timestamp: 2024-10-22T10:50:41.311Z
Learning: When using `assertExhaustive` in a `switch` statement in TypeScript (e.g., in the `shouldRetryError` function in `packages/core/src/v3/errors.ts`), and it throws an error, it's acceptable not to add a `return` statement afterward, as control flow will not proceed beyond the `assertExhaustive` call.

Applied to files:

  • packages/cli-v3/src/commands/deploy.ts
🧬 Code graph analysis (2)
packages/cli-v3/src/build/buildWorker.ts (2)
packages/cli-v3/src/build/extensions.ts (1)
  • createBuildContext (57-119)
packages/cli-v3/src/utilities/windows.ts (1)
  • spinner (115-116)
packages/cli-v3/src/build/extensions.ts (2)
packages/core/src/v3/build/extensions.ts (2)
  • BuildLogger (29-35)
  • BuildExtension (14-22)
packages/cli-v3/src/utilities/windows.ts (1)
  • spinner (115-116)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (12)
packages/cli-v3/package.json (1)

98-98: Based on verification results, all three new dependencies are compatible with the Node.js engine requirement (>=18.20.0) and have no known security vulnerabilities:

  • @s2-dev/[email protected]: Legitimate package from the s2-streamstore project (actively maintained), no engine requirement specified, not deprecated.
  • [email protected]: Requires Node >= 4, well-established package, no reported vulnerabilities.
  • [email protected]: Requires Node >= 18, latest stable version (v7.x branch). Historical vulnerabilities affected older v4.x, v5.x, and v6.x branches; this version is unaffected.

All dependencies are compatible and secure for production use.

packages/cli-v3/src/build/buildWorker.ts (1)

53-67: Verify log level handling in plain mode.

In plain mode, debug, log, and warn all route to console.log, which eliminates the distinction between log levels. This means debug output will always appear (potentially verbose) and warnings won't stand out from regular logs.

Consider whether this is the intended behavior:

  • Should warnings use console.warn to maintain distinction?
  • Should debug logging be conditionally enabled based on a debug flag?

If the current approach is intentional for plain mode simplicity, no changes are needed.

packages/cli-v3/src/build/extensions.ts (1)

57-76: LGTM: Clean logger injection pattern.

The optional logger parameter with fallback to default logging is well-designed. This enables plain mode logging (used in buildWorker) while preserving existing behavior when no custom logger is provided.

packages/cli-v3/src/commands/deploy.ts (9)

81-83: LGTM!

The new CLI options are properly typed with sensible defaults. The detach option correctly implies nativeBuildServer at line 186.


312-322: LGTM!

The native build server path cleanly separates the new deployment workflow from the existing path, with an early return to prevent fallthrough.


1026-1029: LGTM!

The detach mode correctly exits early after initialization, allowing users to queue deployments without waiting.


1074-1133: LGTM!

The event streaming loop is well-structured with proper error handling, graceful degradation for unknown events, and correct use of TypeScript's exhaustiveness checking with satisfies never. The abort controller correctly terminates the stream when the finalized event arrives.


1135-1164: LGTM!

The edge case handling correctly addresses scenarios where the stream terminates unexpectedly, providing clear error messages and deployment links for debugging. This defensive coding improves reliability.


1166-1260: LGTM!

The switch statement correctly handles all deployment result cases with proper control flow. The explicit return statements after process.exit(0) address the previous linter concern, and the default case helpfully documents forward compatibility for future enum values.


1281-1291: LGTM!

The DeploymentEventFromString transformer correctly implements the Zod pattern for parsing and validating JSON strings, with proper error handling via ctx.addIssue and z.NEVER.


205-207: LGTM!

The plain mode integration is consistent throughout the deployment flow, correctly suppressing interactive elements (intro, spinners, formatted links) and using direct console output when --plain is specified.

Also applies to: 222-222, 329-329, 345-345, 411-411, 453-453, 460-470, 495-498, 592-602, 612-615, 639-672


6-8: Verify API patterns for S2 library version ^0.17.6.

I was unable to locate comprehensive documentation for @s2-dev/streamstore version 0.17.6 specifically. The authenticated S2 client is initialized with accessToken, which matches the code at line 1046. However, the usage pattern in the code (s2.basin().stream().readSession()) does not appear in the available documentation for the latest TypeScript SDK versions. The methods basin(), stream(), and readSession() were not found in the documented REST API examples.

This could indicate either:

  1. Version 0.17.6 exposes lower-level gRPC APIs directly, which differ from the documented REST API surface
  2. The API has changed significantly between versions
  3. These are internal/undocumented methods

Please verify that the S2 API usage at lines 1046-1073 aligns with the actual type definitions and available methods in version 0.17.6 of @s2-dev/streamstore.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
packages/cli-v3/src/commands/deploy.ts (1)

1173-1291: This issue was previously flagged but appears unresolved.

The "succeeded" case (line 1203) and default case (line 1289) still call process.exit(0) without an explicit return statement, triggering Biome's noFallthroughSwitchClause lint error. The previous review comment included fixes, but they don't appear to be applied in the current code.

Add explicit return; statements:

       outro(
         `Version ${deployment.version} was deployed ${
           isLinksSupported
             ? `| ${cliLink("Test tasks", rawTestLink)} | ${cliLink(
                 "View deployment",
                 rawDeploymentLink
               )}`
             : ""
         }`
       );
-      return process.exit(0);
+      process.exit(0);
+      return;
     }
       outro(
         `Version ${deployment.version} ${
           isLinksSupported
             ? `| ${cliLink("Test tasks", rawTestLink)} | ${cliLink(
                 "View deployment",
                 rawDeploymentLink
               )}`
             : ""
         }`
       );
-      return process.exit(0);
+      process.exit(0);
+      return;
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ba49783 and f0cd177.

📒 Files selected for processing (2)
  • packages/cli-v3/src/commands/deploy.ts (18 hunks)
  • packages/cli-v3/src/deploy/buildImage.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli-v3/src/deploy/buildImage.ts
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2685
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings/route.tsx:1234-1257
Timestamp: 2025-11-14T19:24:39.536Z
Learning: In the trigger.dev project, version validation for the `useNativeBuildServer` setting cannot be performed at the settings form level because the SDK version is only known at build/deployment time, not when saving project settings.
📚 Learning: 2024-10-22T10:50:41.311Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 1424
File: packages/core/src/v3/errors.ts:155-189
Timestamp: 2024-10-22T10:50:41.311Z
Learning: When using `assertExhaustive` in a `switch` statement in TypeScript (e.g., in the `shouldRetryError` function in `packages/core/src/v3/errors.ts`), and it throws an error, it's acceptable not to add a `return` statement afterward, as control flow will not proceed beyond the `assertExhaustive` call.

Applied to files:

  • packages/cli-v3/src/commands/deploy.ts
🧬 Code graph analysis (1)
packages/cli-v3/src/commands/deploy.ts (7)
packages/cli-v3/src/utilities/tempDirectories.ts (1)
  • getTmpDir (21-49)
packages/cli-v3/src/utilities/windows.ts (1)
  • spinner (115-116)
packages/cli-v3/src/mcp/logger.ts (1)
  • log (14-23)
packages/cli-v3/src/utilities/cliOutput.ts (4)
  • isLinksSupported (7-7)
  • chalkError (24-26)
  • cliLink (140-145)
  • chalkGrey (20-22)
packages/cli-v3/src/apiClient.ts (1)
  • CliApiClient (59-810)
packages/cli-v3/src/deploy/archiveContext.ts (1)
  • createContextArchive (91-149)
packages/core/src/v3/schemas/api.ts (4)
  • DeploymentFinalizedEvent (592-598)
  • DeploymentFinalizedEvent (607-607)
  • DeploymentEvent (600-603)
  • DeploymentEvent (605-605)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (12)
packages/cli-v3/src/commands/deploy.ts (12)

1-60: LGTM: Imports are appropriate for the new native build server functionality.

All newly imported modules (S2 for event streaming, artifact management utilities, and chalk styling helpers) are properly utilized in the native build server deployment flow.


81-83: LGTM: Schema additions are well-defined.

The new boolean options (nativeBuildServer, detach, plain) have appropriate default values and are properly integrated with the command configuration.


176-188: LGTM: Command options are properly configured.

The --detach option correctly implies --native-build-server using Commander's .implies() method, ensuring logical consistency. The --plain option is appropriately hidden from help output.


205-207: LGTM: Plain mode conditionally skips intro.

Appropriately suppresses the intro prompt when plain mode is enabled, which is useful for CI environments and automated workflows.


312-322: LGTM: Clean separation of native build server flow.

The early return when nativeBuildServer is enabled provides clean separation from the standard deployment flow, with all necessary context (apiClient, config, dashboardUrl, userId, gitMeta) passed to the handler.


905-977: LGTM: Archive creation and upload flow is well-structured.

The artifact upload sequence properly:

  • Creates a temporary archive with automatic cleanup
  • Obtains presigned upload credentials from the API
  • Constructs FormData with the required fields
  • Handles cleanup failures gracefully (lines 966-969) without throwing

Note: The upload error handling at lines 959-963 has been flagged in a previous review comment.


978-1025: LGTM: Native deployment initialization is correctly implemented.

Key highlights:

  • contentHash: "-" is appropriate for native builds where the manifest hasn't been built yet (line 979)
  • isNativeBuild: true flag properly distinguishes native from standard builds (line 984), consistent with line 378
  • Path normalization for Windows (line 976) prevents issues with backslash separators
  • GitHub Actions outputs are set early, enabling the --detach mode to exit with useful metadata

1027-1030: LGTM: Detach mode provides clean early exit.

When --detach is specified, the command exits immediately after queuing the deployment, which is useful for CI pipelines that don't need to wait for build completion.


1042-1061: LGTM: S2 event stream setup is correctly configured.

The stream configuration properly:

  • Uses the access token from the deployment response
  • Sets a reasonable 20-minute timeout for build operations (line 1055)
  • Includes an AbortController for clean stream termination (lines 1045, 1058)
  • Wraps the async operation in tryCatch for error handling

1075-1140: LGTM: Event streaming loop is robust and well-structured.

Excellent implementation:

  • Gracefully handles parse failures by logging and skipping invalid records (lines 1082-1088)
  • Uses satisfies never in the default case (line 1135) for compile-time exhaustiveness checking
  • Properly manages spinner state transitions (lines 1094-1098)
  • Formats log messages with appropriate severity styling (lines 1110-1118)
  • Cleanly terminates the stream when finalized (lines 1131-1132)

1142-1171: LGTM: Comprehensive edge case handling.

These conditional checks handle rare but possible scenarios:

  1. Build never dequeued from the queue (lines 1142-1155)
  2. Stream terminated prematurely after build started (lines 1157-1171)

Both cases provide clear error messages and appropriate links to the dashboard, demonstrating good defensive programming.


1312-1322: LGTM: Robust JSON parsing schema.

The DeploymentEventFromString schema correctly:

  • Parses JSON strings with proper error handling (lines 1315-1320)
  • Pipes the result into the DeploymentEvent discriminated union for type safety (line 1322)
  • Returns z.NEVER on parse failure to halt validation

This is a solid pattern for validating streamed event data.

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