fix(core): define RunEvent schema and update ApiClient validation#3220
fix(core): define RunEvent schema and update ApiClient validation#3220bharathkumar39293 wants to merge 6 commits intotriggerdotdev:mainfrom
Conversation
🦋 Changeset detectedLatest commit: fd2f823 The changes in this PR will be included in the next version bump. This PR includes changesets to release 28 packages
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 |
WalkthroughAdds event-driven schemas: TaskEventLevel enum, NanosecondTimestampSchema (coerces nanosecond/millisecond/string inputs to Date), RunEvent (fields: spanId, parentId, runId, message, style, startTime, duration, isError, isPartial, isCancelled, level, events, kind, attemptNumber, taskSlug) and ListRunEventsResponse (events array). Exports types for these schemas. Replaces a previous generic response schema in ApiClient.listRunEvents with ListRunEventsResponse. Tests added/expanded to validate RunEvent and ListRunEventsResponse parsing, date coercion, and optional/null behaviors. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/core/src/v3/apiClient/index.ts (1)
31-31: Consider removing unused import.
RunEventis imported on line 46 but doesn't appear to be used directly in this file. OnlyListRunEventsResponseis used at line 705. TheRunEventtype is already part ofListRunEventsResponse.events, so consumers can access it via the response type if needed.🧹 Proposed fix to remove unused import
import { AddTagsRequestBody, ApiDeploymentListOptions, ApiDeploymentListResponseItem, ApiDeploymentListSearchParams, AppendToStreamResponseBody, BatchItemNDJSON, BatchTaskRunExecutionResult, BatchTriggerTaskV3RequestBody, BatchTriggerTaskV3Response, CanceledRunResponse, CompleteWaitpointTokenRequestBody, CompleteWaitpointTokenResponseBody, CreateBatchRequestBody, CreateBatchResponse, CreateEnvironmentVariableRequestBody, CreateInputStreamWaitpointRequestBody, CreateInputStreamWaitpointResponseBody, CreateScheduleOptions, CreateStreamResponseBody, CreateUploadPayloadUrlResponseBody, CreateWaitpointTokenRequestBody, CreateWaitpointTokenResponseBody, DeletedScheduleObject, EnvironmentVariableResponseBody, EnvironmentVariableWithSecret, ListQueueOptions, ListRunEventsResponse, ListRunResponseItem, ListScheduleOptions, QueueItem, QueueTypeName, QueryExecuteRequestBody, QueryExecuteResponseBody, QueryExecuteCSVResponseBody, ReplayRunResponse, RescheduleRunRequestBody, ResetIdempotencyKeyResponse, RetrieveBatchV2Response, RetrieveQueueParam, RetrieveRunResponse, RetrieveRunTraceResponseBody, - RunEvent, ScheduleObject, SendInputStreamResponseBody, StreamBatchItemsResponse,Also applies to: 46-46
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/core/src/v3/apiClient/index.ts` at line 31, Remove the unused RunEvent import from the module: locate the import list that currently includes RunEvent (alongside ListRunEventsResponse) and delete only RunEvent, leaving ListRunEventsResponse intact; confirm no other references to the RunEvent identifier exist in this file (consumers can access it via ListRunEventsResponse.events) and run a typecheck to ensure the removal is safe.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/core/src/v3/apiClient/index.ts`:
- Line 31: Remove the unused RunEvent import from the module: locate the import
list that currently includes RunEvent (alongside ListRunEventsResponse) and
delete only RunEvent, leaving ListRunEventsResponse intact; confirm no other
references to the RunEvent identifier exist in this file (consumers can access
it via ListRunEventsResponse.events) and run a typecheck to ensure the removal
is safe.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 1cd5cb80-8c72-45a8-855e-ee9ff0ad7de8
📒 Files selected for processing (4)
.changeset/define-runevent-schema.mdpackages/core/src/v3/apiClient/index.tspackages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/schemas/api.ts
📜 Review details
⏰ 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). (13)
- 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 (5, 8)
- 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 (2, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 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 / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: typecheck / typecheck
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{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}: Use task export syntax: export const myTask = task({ id: 'my-task', run: async (payload) => { ... } })
Use Run Engine 2.0 (@internal/run-engine) and redis-worker for all new work - avoid DEPRECATED zodworker (Graphile-worker wrapper)
Prisma 6.14.0 client and schema use PostgreSQL in internal-packages/database - import only from Prisma client
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/apiClient/index.tspackages/core/src/v3/schemas/api.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use zod for validation in packages/core and apps/webapp
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/apiClient/index.tspackages/core/src/v3/schemas/api.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use function declarations instead of default exports
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/apiClient/index.tspackages/core/src/v3/schemas/api.ts
**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use vitest for all tests in the Trigger.dev repository
Files:
packages/core/src/v3/schemas/api-type.test.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/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/apiClient/index.tspackages/core/src/v3/schemas/api.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}
📄 CodeRabbit inference engine (AGENTS.md)
Format code using Prettier before committing
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/apiClient/index.tspackages/core/src/v3/schemas/api.ts
**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.test.{ts,tsx,js,jsx}: Test files should live beside the files under test and use descriptivedescribeanditblocks
Tests should avoid mocks or stubs and use the helpers from@internal/testcontainerswhen Redis or Postgres are needed
Use vitest for running unit tests
Files:
packages/core/src/v3/schemas/api-type.test.ts
packages/core/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (packages/core/CLAUDE.md)
Never import the root package (
@trigger.dev/core). Always use subpath imports such as@trigger.dev/core/v3,@trigger.dev/core/v3/utils,@trigger.dev/core/logger, or@trigger.dev/core/schemas
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/apiClient/index.tspackages/core/src/v3/schemas/api.ts
**/*.test.{ts,tsx,js}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.test.{ts,tsx,js}: Use vitest exclusively for testing - never mock anything, use testcontainers instead
Place test files next to source files with naming convention: SourceFile.ts -> SourceFile.test.ts
Files:
packages/core/src/v3/schemas/api-type.test.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use testcontainers for Redis/PostgreSQL testing instead of mocks with redisTest, postgresTest, or containerTest helpers from
@internal/testcontainers
Files:
packages/core/src/v3/schemas/api-type.test.ts
{packages,integrations}/**/*.{ts,tsx,js,json}
📄 CodeRabbit inference engine (CLAUDE.md)
When modifying public packages (packages/* or integrations/*), add a changeset using pnpm run changeset:add with default patch level for bug fixes and minor changes
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/apiClient/index.tspackages/core/src/v3/schemas/api.ts
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js}: Always import from@trigger.dev/sdkfor Trigger.dev tasks - never use@trigger.dev/sdk/v3or deprecated client.defineJob
Import subpaths only from@trigger.dev/core, never import from root
Add crumbs as you write code using //@crumbscomments or //#region@crumbsblocks for agentcrumbs debug tracing
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/apiClient/index.tspackages/core/src/v3/schemas/api.ts
🧠 Learnings (25)
📓 Common learnings
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schemaTask()` from `trigger.dev/sdk/v3` with Zod schema for payload validation
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schemaTask()` from `trigger.dev/sdk/v3` with Zod schema for payload validation
Applied to files:
.changeset/define-runevent-schema.mdpackages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:43:25.254Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/run-engine/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:25.254Z
Learning: Applies to internal-packages/run-engine/src/engine/tests/**/*.test.ts : Implement tests for RunEngine in `src/engine/tests/` using testcontainers for Redis and PostgreSQL containerization
Applied to files:
packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2026-01-15T10:48:02.687Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-15T10:48:02.687Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vitest for running unit tests
Applied to files:
packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Use vitest for all tests in the Trigger.dev repository
Applied to files:
packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2026-01-15T10:48:02.687Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-15T10:48:02.687Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Test files should live beside the files under test and use descriptive `describe` and `it` blocks
Applied to files:
packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: Applies to apps/webapp/app/v3/services/**/*.server.ts : When editing services that branch on `RunEngineVersion` to support both V1 and V2 (e.g., `cancelTaskRun.server.ts`, `batchTriggerV3.server.ts`), only modify V2 code paths
Applied to files:
packages/core/src/v3/apiClient/index.ts
📚 Learning: 2026-03-02T12:43:25.254Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/run-engine/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:25.254Z
Learning: Applies to internal-packages/run-engine/src/engine/systems/**/*.ts : Integrate OpenTelemetry tracer and meter instrumentation in RunEngine systems for observability
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to **/*.{ts,tsx} : Use task export syntax: export const myTask = task({ id: 'my-task', run: async (payload) => { ... } })
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `.withStreams()` to subscribe to realtime streams from task metadata in addition to run changes
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Subscribe to run updates using `runs.subscribeToRun()` for realtime monitoring of task execution
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Attach metadata to task runs using the metadata option when triggering, and access/update it inside runs using metadata functions
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to {packages,integrations}/**/*.{ts,tsx,js,json} : When modifying public packages (packages/* or integrations/*), add a changeset using pnpm run changeset:add with default patch level for bug fixes and minor changes
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Export tasks with unique IDs within the project to enable proper task discovery and execution
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure OpenTelemetry instrumentations and exporters in trigger.config.ts for enhanced logging
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to **/*.{ts,tsx} : Use Run Engine 2.0 (internal/run-engine) and redis-worker for all new work - avoid DEPRECATED zodworker (Graphile-worker wrapper)
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: Target Run Engine V2 for all new code; the `engineVersion.server.ts` file determines V1 vs V2 for a given environment
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Use the Run Engine 2.0 from `internal/run-engine` for new run lifecycle code in the webapp instead of the legacy run engine
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: V1-only legacy code is located in `app/v3/marqs/`, `app/v3/legacyRunEngineWorker.server.ts`, `app/v3/services/triggerTaskV1.server.ts`, `app/v3/services/cancelTaskRunV1.server.ts`, `app/v3/authenticatedSocketConnection.server.ts`, and `app/v3/sharedSocketConnection.ts`
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: All run lifecycle operations (triggering, completing, cancelling, etc.) should be performed through the singleton run engine instance in `app/v3/runEngine.server.ts` via service calls
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:43:17.177Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:17.177Z
Learning: New code should always target Prisma RunEngineVersion V2 (run-engine + redis-worker), not V1 (legacy MarQS + Graphile)
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: Applies to apps/webapp/app/v3/*Worker.server.ts : New background job workers should use `trigger.dev/redis-worker` (e.g., `commonWorker.server.ts`, `alertsWorker.server.ts`, `batchTriggerWorker.server.ts`), not zodworker or graphile-worker
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Export every task, including subtasks
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use the `task()` function from `trigger.dev/sdk/v3` to define tasks with id and run properties
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to {packages/core,apps/webapp}/**/*.{ts,tsx} : Use zod for validation in packages/core and apps/webapp
Applied to files:
packages/core/src/v3/schemas/api.ts
🔇 Additional comments (9)
packages/core/src/v3/schemas/api.ts (4)
12-13: LGTM!The imports for
TaskEventStyleandSpanEventsare correctly added to support the newRunEventschema definition.
1644-1645: LGTM!
TaskEventLevelusesz.enum()which produces a TypeScript string union type, consistent with other similar definitions in this file (e.g.,RunStatus,AttemptStatus,BatchStatus).
1647-1664: LGTM!The
RunEventschema is well-structured:
- Uses
.nullish()forparentIdto correctly handle root spans whereparentIdmay benullfrom the DB- Uses
z.coerce.date()forstartTime, consistent with other date fields in this file- Properly references existing schemas (
TaskEventStyle,TaskEventLevel,SpanEvents)
1666-1670: LGTM!The
ListRunEventsResponsewrapper correctly encapsulates the events array in an object, providing a proper response shape that can be extended in the future without breaking changes..changeset/define-runevent-schema.md (1)
1-5: LGTM!The changeset is properly formatted with
patchlevel, which is appropriate for this bug fix that adds strict schema validation to replacez.any().packages/core/src/v3/apiClient/index.ts (1)
703-713: LGTM!The
listRunEventsmethod now usesListRunEventsResponseschema instead ofz.any(), providing strict validation for the API response. This is the core fix for the internal TODO mentioned in the PR objectives.packages/core/src/v3/schemas/api-type.test.ts (3)
2-2: LGTM!Imports correctly added for the new schemas to be tested.
143-200: LGTM!Comprehensive test coverage for
RunEventschema:
- Valid event parsing with date coercion verification
- Missing required field detection
- Invalid enum value rejection
- Both
undefined(missing) andnullparentId handlingThe tests align well with the schema definition and PR objectives.
202-233: LGTM!Good test coverage for
ListRunEventsResponse:
- Validates the wrapper object structure
- Correctly verifies that a plain array fails, ensuring the
{ events: [...] }wrapper is requiredThe tests confirm the API response shape change is properly enforced.
| isCancelled: z.boolean(), | ||
| level: TaskEventLevel, | ||
| events: SpanEvents.optional(), | ||
| kind: z.string(), |
There was a problem hiding this comment.
📝 Info: ClickHouse getRunEvents hardcodes kind to 'UNSPECIFIED' and omits taskSlug
The ClickHouse #spanSummaryToRunPreparedEvent (apps/webapp/app/v3/eventRepository/clickhouseEventRepository.server.ts:1908-1925) hardcodes kind: "UNSPECIFIED" and does not include taskSlug. The RunEvent schema handles both: kind is z.string() so "UNSPECIFIED" is valid, and taskSlug is .optional(). The Prisma-based getRunEvents (apps/webapp/app/v3/eventRepository/eventRepository.server.ts:723-726) filters out kind === "UNSPECIFIED" events before returning, but the ClickHouse version doesn't—so ClickHouse-backed responses will have all events with kind: "UNSPECIFIED". This is pre-existing behavior and not caused by this PR, but it means the kind field is not very meaningful for ClickHouse-sourced events.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/core/src/v3/schemas/api.ts`:
- Around line 1646-1666: NanosecondTimestampSchema's transform can return
invalid Dates and never accepts Date inputs; update the schema to include
z.date() in the union so Date values reach the transform (or handle them via a
preprocess) and then validate the transformed value by adding a refine that
checks !isNaN(date.getTime()) with a clear error message; reference
NanosecondTimestampSchema and ensure the transform still handles 19- and
13-digit strings but add the post-transform validation (or replace transform
with preprocess+parse and then z.date() to guarantee a validated Date).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 2b895805-270f-4e5f-8479-59c111f5f1db
📒 Files selected for processing (2)
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/schemas/api.ts
📜 Review details
⏰ 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). (3)
- GitHub Check: units / internal / 📊 Merge Reports
- GitHub Check: units / packages / 📊 Merge Reports
- GitHub Check: typecheck / typecheck
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{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}: Use task export syntax: export const myTask = task({ id: 'my-task', run: async (payload) => { ... } })
Use Run Engine 2.0 (@internal/run-engine) and redis-worker for all new work - avoid DEPRECATED zodworker (Graphile-worker wrapper)
Prisma 6.14.0 client and schema use PostgreSQL in internal-packages/database - import only from Prisma client
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/schemas/api.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use zod for validation in packages/core and apps/webapp
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/schemas/api.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use function declarations instead of default exports
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/schemas/api.ts
**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use vitest for all tests in the Trigger.dev repository
Files:
packages/core/src/v3/schemas/api-type.test.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/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/schemas/api.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}
📄 CodeRabbit inference engine (AGENTS.md)
Format code using Prettier before committing
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/schemas/api.ts
**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.test.{ts,tsx,js,jsx}: Test files should live beside the files under test and use descriptivedescribeanditblocks
Tests should avoid mocks or stubs and use the helpers from@internal/testcontainerswhen Redis or Postgres are needed
Use vitest for running unit tests
Files:
packages/core/src/v3/schemas/api-type.test.ts
packages/core/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (packages/core/CLAUDE.md)
Never import the root package (
@trigger.dev/core). Always use subpath imports such as@trigger.dev/core/v3,@trigger.dev/core/v3/utils,@trigger.dev/core/logger, or@trigger.dev/core/schemas
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/schemas/api.ts
**/*.test.{ts,tsx,js}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.test.{ts,tsx,js}: Use vitest exclusively for testing - never mock anything, use testcontainers instead
Place test files next to source files with naming convention: SourceFile.ts -> SourceFile.test.ts
Files:
packages/core/src/v3/schemas/api-type.test.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use testcontainers for Redis/PostgreSQL testing instead of mocks with redisTest, postgresTest, or containerTest helpers from
@internal/testcontainers
Files:
packages/core/src/v3/schemas/api-type.test.ts
{packages,integrations}/**/*.{ts,tsx,js,json}
📄 CodeRabbit inference engine (CLAUDE.md)
When modifying public packages (packages/* or integrations/*), add a changeset using pnpm run changeset:add with default patch level for bug fixes and minor changes
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/schemas/api.ts
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js}: Always import from@trigger.dev/sdkfor Trigger.dev tasks - never use@trigger.dev/sdk/v3or deprecated client.defineJob
Import subpaths only from@trigger.dev/core, never import from root
Add crumbs as you write code using //@crumbscomments or //#region@crumbsblocks for agentcrumbs debug tracing
Files:
packages/core/src/v3/schemas/api-type.test.tspackages/core/src/v3/schemas/api.ts
🧠 Learnings (29)
📓 Common learnings
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schemaTask()` from `trigger.dev/sdk/v3` with Zod schema for payload validation
📚 Learning: 2026-03-02T12:43:25.254Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/run-engine/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:25.254Z
Learning: Applies to internal-packages/run-engine/src/engine/tests/**/*.test.ts : Implement tests for RunEngine in `src/engine/tests/` using testcontainers for Redis and PostgreSQL containerization
Applied to files:
packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2026-01-15T10:48:02.687Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-15T10:48:02.687Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vitest for running unit tests
Applied to files:
packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Use vitest for all tests in the Trigger.dev repository
Applied to files:
packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2026-01-15T10:48:02.687Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-15T10:48:02.687Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Test files should live beside the files under test and use descriptive `describe` and `it` blocks
Applied to files:
packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schemaTask()` from `trigger.dev/sdk/v3` with Zod schema for payload validation
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:43:25.254Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/run-engine/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:25.254Z
Learning: Applies to internal-packages/run-engine/src/engine/systems/**/*.ts : Integrate OpenTelemetry tracer and meter instrumentation in RunEngine systems for observability
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to **/*.{ts,tsx} : Use task export syntax: export const myTask = task({ id: 'my-task', run: async (payload) => { ... } })
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Attach metadata to task runs using the metadata option when triggering, and access/update it inside runs using metadata functions
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `.withStreams()` to subscribe to realtime streams from task metadata in addition to run changes
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Subscribe to run updates using `runs.subscribeToRun()` for realtime monitoring of task execution
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to {packages,integrations}/**/*.{ts,tsx,js,json} : When modifying public packages (packages/* or integrations/*), add a changeset using pnpm run changeset:add with default patch level for bug fixes and minor changes
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Export tasks with unique IDs within the project to enable proper task discovery and execution
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to **/*.{ts,tsx} : Prisma 6.14.0 client and schema use PostgreSQL in internal-packages/database - import only from Prisma client
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `trigger.dev/sdk/v3` for all imports in Trigger.dev tasks
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:42:47.903Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3213
File: apps/webapp/app/routes/admin.api.v1.llm-models.$modelId.ts:40-43
Timestamp: 2026-03-13T13:42:47.903Z
Learning: In `apps/webapp/app/routes/admin.api.v1.llm-models.$modelId.ts` and `apps/webapp/app/routes/admin.api.v1.llm-models.ts`, the `startDate` field in `UpdateModelSchema` and `CreateModelSchema` intentionally uses `z.string().optional()` (or `.nullable().optional()`) without strict ISO datetime validation. Invalid date strings are rejected at the Prisma/DB layer. This is acceptable because these are admin-only API routes protected by Personal Access Token (PAT) authentication and are not user-facing.
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-01-28T14:15:15.011Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 2953
File: apps/webapp/app/components/runs/v3/SharedFilters.tsx:441-452
Timestamp: 2026-01-28T14:15:15.011Z
Learning: In apps/webapp/app/components/runs/v3/SharedFilters.tsx, the maxPeriodDays limit for date ranges should only check the from date (via dateRangeToDays(fromValue)) because it enforces data retention limits—how far back in history queries can reach. The to date is irrelevant for retention-based limits.
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-08-14T10:09:02.528Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2390
File: internal-packages/run-engine/src/engine/index.ts:466-467
Timestamp: 2025-08-14T10:09:02.528Z
Learning: In the triggerdotdev/trigger.dev codebase, it's acceptable to pass `string | undefined` types directly to Prisma operations (both create and update). The codebase consistently uses this pattern and the team is comfortable with how Prisma handles undefined values.
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-07-12T18:06:04.133Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 2264
File: apps/webapp/app/services/runsRepository.server.ts:172-174
Timestamp: 2025-07-12T18:06:04.133Z
Learning: In apps/webapp/app/services/runsRepository.server.ts, the in-memory status filtering after fetching runs from Prisma is intentionally used as a workaround for ClickHouse data delays. This approach is acceptable because the result set is limited to a maximum of 100 runs due to pagination, making the performance impact negligible.
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: Applies to apps/webapp/app/v3/services/**/*.server.ts : When editing services that branch on `RunEngineVersion` to support both V1 and V2 (e.g., `cancelTaskRun.server.ts`, `batchTriggerV3.server.ts`), only modify V2 code paths
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use the `task()` function from `trigger.dev/sdk/v3` to define tasks with id and run properties
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to **/*.{ts,tsx} : Use Run Engine 2.0 (internal/run-engine) and redis-worker for all new work - avoid DEPRECATED zodworker (Graphile-worker wrapper)
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: Target Run Engine V2 for all new code; the `engineVersion.server.ts` file determines V1 vs V2 for a given environment
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Use the Run Engine 2.0 from `internal/run-engine` for new run lifecycle code in the webapp instead of the legacy run engine
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: V1-only legacy code is located in `app/v3/marqs/`, `app/v3/legacyRunEngineWorker.server.ts`, `app/v3/services/triggerTaskV1.server.ts`, `app/v3/services/cancelTaskRunV1.server.ts`, `app/v3/authenticatedSocketConnection.server.ts`, and `app/v3/sharedSocketConnection.ts`
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: All run lifecycle operations (triggering, completing, cancelling, etc.) should be performed through the singleton run engine instance in `app/v3/runEngine.server.ts` via service calls
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:43:17.177Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:17.177Z
Learning: New code should always target Prisma RunEngineVersion V2 (run-engine + redis-worker), not V1 (legacy MarQS + Graphile)
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: Applies to apps/webapp/app/v3/*Worker.server.ts : New background job workers should use `trigger.dev/redis-worker` (e.g., `commonWorker.server.ts`, `alertsWorker.server.ts`, `batchTriggerWorker.server.ts`), not zodworker or graphile-worker
Applied to files:
packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to {packages/core,apps/webapp}/**/*.{ts,tsx} : Use zod for validation in packages/core and apps/webapp
Applied to files:
packages/core/src/v3/schemas/api.ts
🔇 Additional comments (2)
packages/core/src/v3/schemas/api-type.test.ts (1)
143-269: Good schema test coverage for the new RunEvent contract.These tests exercise success/failure paths, nullish handling, coercion behavior, and wrapped response parsing well.
packages/core/src/v3/schemas/api.ts (1)
1688-1692: List response wrapper schema is clean and explicit.Using a dedicated
{ events: RunEvent[] }schema here is a solid upgrade over generic parsing.
| export const NanosecondTimestampSchema = z | ||
| .union([z.string(), z.number(), z.bigint()]) | ||
| .transform((val) => { | ||
| // If it's already a Date, return it (though union doesn't include it) | ||
| if (typeof val === "object" && val instanceof Date) return val; | ||
|
|
||
| const str = val.toString(); | ||
|
|
||
| // 19 digits is nanoseconds (e.g., 1710374400000000000) | ||
| if (str.length === 19) { | ||
| return new Date(Number(BigInt(str) / 1000000n)); | ||
| } | ||
|
|
||
| // 13 digits is milliseconds | ||
| if (str.length === 13) { | ||
| return new Date(Number(val)); | ||
| } | ||
|
|
||
| // Default to standard date coercion | ||
| return new Date(val as any); | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Zod v3, does .transform()automatically validate that a returnedDateis valid, and will a transform onz.union([z.string(), z.number(), z.bigint()])run when the input is aDate object?
💡 Result:
-
No. In Zod v3,
.transform()runs after the input schema has parsed; Zod does not automatically re-validate the returned value (e.g., it won’t automatically reject anInvalid Date). If you need that, you must either add a check inside the transform viactx(add an issue) or “pipe” into an output schema (e.g. az.date()schema) to validate the post-transform value. [1], [2] -
No. A
.transform()attached toz.union([z.string(), z.number(), z.bigint()])will only run if the union successfully parses the input. If the input is aDateobject, none of those union branches match, so parsing fails and the transform is not executed. [3], [2]
Sources:
[1] Zod docs – Transforms API (z.transform, using ctx.issues for validation) https://zod.dev/api?id=preprocess
[2] Zod v3 README (npm) – ZodEffects runs transforms post-parsing https://www.npmjs.com/package/zod/v/3.0.0-alpha.19
[3] Zod docs – unions return the first option that validates successfully (i.e., must validate to proceed) https://zod.dev/?id=dates-1
Nanosecond timestamp transform does not validate returned Date and misses literal Date inputs.
In Zod v3, .transform() does not automatically validate its returned value, so invalid timestamps can produce Invalid Date objects that pass through. Additionally, the unreachable Date branch check is correct—since the union excludes z.date(), a literal Date input fails parsing before the transform runs.
🔧 Proposed fix
export const NanosecondTimestampSchema = z
- .union([z.string(), z.number(), z.bigint()])
+ .union([z.string(), z.number(), z.bigint(), z.date()])
.transform((val) => {
- // If it's already a Date, return it (though union doesn't include it)
- if (typeof val === "object" && val instanceof Date) return val;
+ if (val instanceof Date) return val;
- const str = val.toString();
+ const str = String(val);
- // 19 digits is nanoseconds (e.g., 1710374400000000000)
- if (str.length === 19) {
+ // 19 digits => nanoseconds
+ if (/^-?\d{19}$/.test(str)) {
return new Date(Number(BigInt(str) / 1000000n));
}
- // 13 digits is milliseconds
- if (str.length === 13) {
- return new Date(Number(val));
+ // 13 digits => milliseconds
+ if (/^-?\d{13}$/.test(str)) {
+ return new Date(Number(str));
}
- // Default to standard date coercion
- return new Date(val as any);
- });
+ return new Date(str);
+ })
+ .pipe(z.date());📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const NanosecondTimestampSchema = z | |
| .union([z.string(), z.number(), z.bigint()]) | |
| .transform((val) => { | |
| // If it's already a Date, return it (though union doesn't include it) | |
| if (typeof val === "object" && val instanceof Date) return val; | |
| const str = val.toString(); | |
| // 19 digits is nanoseconds (e.g., 1710374400000000000) | |
| if (str.length === 19) { | |
| return new Date(Number(BigInt(str) / 1000000n)); | |
| } | |
| // 13 digits is milliseconds | |
| if (str.length === 13) { | |
| return new Date(Number(val)); | |
| } | |
| // Default to standard date coercion | |
| return new Date(val as any); | |
| }); | |
| export const NanosecondTimestampSchema = z | |
| .union([z.string(), z.number(), z.bigint(), z.date()]) | |
| .transform((val) => { | |
| if (val instanceof Date) return val; | |
| const str = String(val); | |
| // 19 digits => nanoseconds | |
| if (/^-?\d{19}$/.test(str)) { | |
| return new Date(Number(BigInt(str) / 1000000n)); | |
| } | |
| // 13 digits => milliseconds | |
| if (/^-?\d{13}$/.test(str)) { | |
| return new Date(Number(str)); | |
| } | |
| return new Date(str); | |
| }) | |
| .pipe(z.date()); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/core/src/v3/schemas/api.ts` around lines 1646 - 1666,
NanosecondTimestampSchema's transform can return invalid Dates and never accepts
Date inputs; update the schema to include z.date() in the union so Date values
reach the transform (or handle them via a preprocess) and then validate the
transformed value by adding a refine that checks !isNaN(date.getTime()) with a
clear error message; reference NanosecondTimestampSchema and ensure the
transform still handles 19- and 13-digit strings but add the post-transform
validation (or replace transform with preprocess+parse and then z.date() to
guarantee a validated Date).
Resolves the internal TODO in
ApiClient
regarding missing schema validation for task run events.
✅ Checklist
I have followed every step in the contributing guide
The PR title follows the convention.
I ran and tested the code works
Technical Cost/Benefit Analysis
Benefit:
Reliability: Replaces z.any() with a strict Zod schema, preventing the SDK from returning invalid or unexpected data formats.
Safety: Addresses two critical edge cases identified during development:
Wrapper Handling: The API returns { events: [...] }. This PR adds the
ListRunEventsResponse
wrapper.
Nullable parentId: Supports null for root spans (stored as null in DB).
Integration: Ensures consistency for tools like the MCP server.
Cost/Risk:
Low Risk: Localized change to @trigger.dev/core. Highly decoupled from other services.
Testing
Unit tests in
packages/core/src/v3/schemas/api-type.test.ts
verify:
Valid event parsing & date coercion.
Failure on invalid data.
Handling of null and undefined for parentId.
Handling of the { events: [...] } response wrapper.
Changelog
@trigger.dev/core: Added
RunEvent
and
ListRunEventsResponse
Zod schemas.
@trigger.dev/core: Updated ApiClient.listRunEvents to use strict validation.