Skip to content

refactor: rename payload to input, add startedAt/completedAt, unify Run types#42

Merged
coji merged 6 commits into
mainfrom
refactor/unify-run-types
Mar 4, 2026
Merged

refactor: rename payload to input, add startedAt/completedAt, unify Run types#42
coji merged 6 commits into
mainfrom
refactor/unify-run-types

Conversation

@coji
Copy link
Copy Markdown
Owner

@coji coji commented Mar 4, 2026

Summary

  • Rename payloadinput across all packages to align with defineJob({ input }) and trigger(input) API naming
  • Add startedAt/completedAt columns to durably_runs table (migration v3) and set them on worker status transitions
  • Derive ClientRun from core Run via Pick<> instead of maintaining a separate interface; remove RunRecord type entirely
  • Update all tests, examples, and documentation

Breaking Changes

  • Run.payloadRun.input
  • RunTriggerEvent.payload / RunStartEvent.payload.input
  • JobRunFunction second parameter renamed from payload to input
  • RunRecord type removed (use ClientRun instead)

Test plan

  • pnpm --filter durably typecheck passes
  • pnpm --filter durably test:node -- --run — 186 tests pass
  • pnpm --filter durably-react typecheck passes
  • pnpm --filter durably-react test -- --run — 140 tests pass
  • pnpm --filter durably-website generate:llms regenerated

Closes #32

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Breaking Changes

    • Job handlers now receive input instead of payload
    • Run objects and emitted run events expose input instead of payload
    • RunRecord renamed to ClientRun in the client API
  • New Features

    • Run execution now records startedAt and completedAt timestamps
  • Documentation

    • Examples and docs updated to reflect the input naming and new timing fields

…un types

- Rename `payload` → `input` across all packages to align with
  `defineJob({ input })` and `trigger(input)` API naming
- Add `startedAt`/`completedAt` columns to durably_runs table (migration v3)
  and set them on worker status transitions
- Derive `ClientRun` from core `Run` via `Pick<>` instead of maintaining
  a separate interface; remove `RunRecord` type entirely
- Update all tests, examples, and documentation

Closes #32

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
durably-demo Ready Ready Preview Mar 4, 2026 10:43pm

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 4, 2026

Warning

Rate limit exceeded

@coji has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 44 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c9695329-e606-42bc-bf04-190840a01447

📥 Commits

Reviewing files that changed from the base of the PR and between fefd953 and f442d47.

📒 Files selected for processing (16)
  • examples/browser-react-router-spa/app/routes/_index/dashboard.tsx
  • examples/browser-vite-react/src/components/dashboard.tsx
  • examples/fullstack-react-router/app/routes/_index/dashboard.tsx
  • packages/durably-react/docs/llms.md
  • packages/durably-react/src/types.ts
  • packages/durably/docs/llms.md
  • packages/durably/src/index.ts
  • packages/durably/src/server.ts
  • packages/durably/src/storage.ts
  • packages/durably/tests/node/core-extensions.test.ts
  • packages/durably/tests/shared/server.shared.ts
  • website/api/durably-react/client.md
  • website/api/durably-react/types.md
  • website/api/http-handler.md
  • website/api/index.md
  • website/public/llms.txt
📝 Walkthrough

Walkthrough

Systematic refactor renaming the job run handler parameter and stored payload field from payloadinput across code, tests, and docs; database schema bumped (v2 → v3) with migration adding input column plus startedAt and completedAt timestamps; client types consolidated to use ClientRun.

Changes

Cohort / File(s) Summary
Example Apps - Jobs
examples/browser-react-router-spa/app/jobs/{data-sync,import-csv,process-image}.ts, examples/browser-vite-react/src/jobs/{data-sync,process-image}.ts, examples/fullstack-react-router/app/jobs/{data-sync,import-csv,process-image}.ts, examples/server-node/jobs/process-image.ts
Renamed job run parameter payloadinput and updated all internal references (e.g., payload.userIdinput.userId). No logic changes.
Core types & events
packages/durably/src/{types,events}.ts, packages/durably-react/src/types.ts, packages/durably-react/docs/llms.md
Public types updated: Run.payloadRun.input; RunTriggerEvent/RunStartEvent use input; TypedRun and related docs updated. ClientRun consolidated/aliased via Pick.
Storage / Schema / Migrations
packages/durably/src/{storage,schema,migrations}.ts
Renamed storage fields/interfaces from payloadinput; added startedAt and completedAt on Run and update inputs; schema version bumped to 3 and migration added to rename column and add timestamp columns.
Job execution & worker
packages/durably/src/{job,worker}.ts
Trigger/batch paths, event emissions, and job invocation now pass input (not payload); worker sets startedAt on run start and completedAt on completion; event payload fields updated.
React client & API surface
packages/durably-react/src/client/{use-run-actions,index}.ts, packages/durably-react/src/client.ts
Removed RunRecord export in favor of ClientRun; getRun return type changed to `Promise<ClientRun
define-job API surface
packages/durably/src/define-job.ts, docs examples
JobRunFunction/JSDoc examples renamed parameter payloadinput.
Tests — shared & suite updates
packages/durably/tests/shared/*, packages/durably/tests/{node,react}/*, packages/durably-react/tests/types.test.ts
Updated test job definitions, assertions and fixtures to use input instead of payload; migration tests updated to expect schema v3 and timestamp presence.
Website / Docs
website/api/*, website/guide/*, website/public/llms.txt
Documentation and examples updated to use input in job run signatures and Run examples; docs reflect new Run fields (startedAt, completedAt) and ClientRun naming.
Misc examples & guides
examples/*, website/* (various)
Consistent parameter rename and example updates across site and guides (CSV import, background-sync, getting-started, etc.).

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client
participant API
participant Storage
participant Worker
participant DB
Client->>API: trigger run(input)
API->>Storage: createRun({ input, ... })
Storage->>DB: insert run row (input)
API->>Client: return run id
Worker->>Storage: claim/run next
Worker->>Storage: update run { status: running, startedAt, heartbeatAt }
Worker->>Worker: job.fn(step, input)
Worker->>Storage: update run { status: success|failed, completedAt, output/error }
Worker->>API: emit run:start / run:complete events (include input)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐇 Payload hopped away today,

Input took its place to play.
Timestamps mark each run’s start and end,
Types made tidy, every branch and bend.
A little rabbit cheers this change — hooray!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly summarizes the main changes: renaming payload to input, adding timestamps, and unifying Run types, which aligns with the changeset objectives.
Linked Issues check ✅ Passed All coding requirements from issue #32 are fully addressed: RunRecord is removed, ClientRun is consolidated as the single source of truth using Pick, and all type duplications are eliminated across the codebase.
Out of Scope Changes check ✅ Passed The PR also includes renaming payload to input and adding startedAt/completedAt timestamps, which are closely related enhancements that support the primary goal of unifying Run types and improving API consistency.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/unify-run-types

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.

- Rename payload→input in all website guide code examples
- Add Run Type section to create-durably.md with full field table
- Add Run Type summary to index.md cheat sheet
- Both include new startedAt/completedAt fields

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
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

🤖 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/durably/src/migrations.ts`:
- Around line 125-145: The v3 migration (version: 3, up: async (db)) performs
multiple DDL steps on table 'durably_runs' (renameColumn 'payload'->'input' and
addColumn 'started_at'/'completed_at') but doesn't record the schema version
atomically; wrap the DDL and the schema-version write in a single transaction so
either all changes and the migration-record insert/update succeed or none do.
Modify the up function to begin a transaction via the DB transaction API (e.g.,
db.transaction(...) or a BEGIN/COMMIT block provided by your DB client), execute
the renameColumn and addColumn calls inside that transaction, then write the
migration version (insert or update your migrations table / schema version
record) inside the same transaction before committing; ensure any error rolls
back so re-running migrations won't see a half-applied state.

In `@packages/durably/src/worker.ts`:
- Around line 251-256: The current two-step claim (getNextPendingRun ->
storage.updateRun) is non-atomic and allows duplicate execution; replace it by
adding a new storage method claimPendingRun that performs an atomic guarded
update (e.g. UPDATE ... SET status='running', heartbeatAt=?, startedAt=? WHERE
id=? AND status='pending') and returns whether a row was affected, then change
the worker to call storage.claimPendingRun(run.id, {status:'running',
heartbeatAt: now, startedAt: now}) instead of storage.updateRun and only proceed
with execution when claimPendingRun reports success (otherwise skip/continue);
reference functions: getNextPendingRun, storage.updateRun, claimPendingRun, and
the worker run claim block in worker.ts.

In `@website/api/durably-react/client.md`:
- Line 401: Update the docs table entry for getRun to indicate it returns a
nullable result: change the return type from Promise<ClientRun> to
Promise<ClientRun | null> so it matches the actual client implementation (see
getRun usage in use-run-actions where it returns ClientRun | null); ensure the
table cell text is updated exactly to "Promise<ClientRun | null>" to avoid
misleading consumers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 64524b5c-77da-4f7f-81e0-225aca40dcce

📥 Commits

Reviewing files that changed from the base of the PR and between ac4f439 and 9fa5be8.

📒 Files selected for processing (46)
  • examples/browser-react-router-spa/app/jobs/data-sync.ts
  • examples/browser-react-router-spa/app/jobs/import-csv.ts
  • examples/browser-react-router-spa/app/jobs/process-image.ts
  • examples/browser-vite-react/src/jobs/data-sync.ts
  • examples/browser-vite-react/src/jobs/process-image.ts
  • examples/fullstack-react-router/app/jobs/data-sync.ts
  • examples/fullstack-react-router/app/jobs/import-csv.ts
  • examples/fullstack-react-router/app/jobs/process-image.ts
  • examples/server-node/jobs/process-image.ts
  • packages/durably-react/docs/llms.md
  • packages/durably-react/src/client.ts
  • packages/durably-react/src/client/index.ts
  • packages/durably-react/src/client/use-run-actions.ts
  • packages/durably-react/src/types.ts
  • packages/durably-react/tests/types.test.ts
  • packages/durably/docs/llms.md
  • packages/durably/src/define-job.ts
  • packages/durably/src/durably.ts
  • packages/durably/src/events.ts
  • packages/durably/src/job.ts
  • packages/durably/src/migrations.ts
  • packages/durably/src/schema.ts
  • packages/durably/src/storage.ts
  • packages/durably/src/worker.ts
  • packages/durably/tests/node/core-extensions.test.ts
  • packages/durably/tests/react/strict-mode.test.tsx
  • packages/durably/tests/shared/concurrency.shared.ts
  • packages/durably/tests/shared/durably.shared.ts
  • packages/durably/tests/shared/events.shared.ts
  • packages/durably/tests/shared/job.shared.ts
  • packages/durably/tests/shared/migrate.shared.ts
  • packages/durably/tests/shared/recovery.shared.ts
  • packages/durably/tests/shared/run-api.shared.ts
  • packages/durably/tests/shared/server.shared.ts
  • packages/durably/tests/shared/step.shared.ts
  • packages/durably/tests/shared/storage.shared.ts
  • packages/durably/tests/shared/worker.shared.ts
  • website/api/create-durably.md
  • website/api/define-job.md
  • website/api/durably-react/browser.md
  • website/api/durably-react/client.md
  • website/api/durably-react/types.md
  • website/api/events.md
  • website/api/index.md
  • website/api/step.md
  • website/public/llms.txt
💤 Files with no reviewable changes (2)
  • packages/durably-react/src/client.ts
  • packages/durably-react/src/client/index.ts

Comment on lines +125 to +145
{
version: 3,
up: async (db) => {
// Rename payload column to input
await db.schema
.alterTable('durably_runs')
.renameColumn('payload', 'input')
.execute()

// Add started_at and completed_at columns
await db.schema
.alterTable('durably_runs')
.addColumn('started_at', 'text')
.execute()

await db.schema
.alterTable('durably_runs')
.addColumn('completed_at', 'text')
.execute()
},
},
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Mar 4, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Make migration v3 application atomic with version recording.

This migration performs multiple DDL steps. If execution stops after renaming payload but before schema version is recorded, re-running migrations can fail because payload no longer exists. Please ensure the migration step and its schema-version write are committed as one atomic unit.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/durably/src/migrations.ts` around lines 125 - 145, The v3 migration
(version: 3, up: async (db)) performs multiple DDL steps on table 'durably_runs'
(renameColumn 'payload'->'input' and addColumn 'started_at'/'completed_at') but
doesn't record the schema version atomically; wrap the DDL and the
schema-version write in a single transaction so either all changes and the
migration-record insert/update succeed or none do. Modify the up function to
begin a transaction via the DB transaction API (e.g., db.transaction(...) or a
BEGIN/COMMIT block provided by your DB client), execute the renameColumn and
addColumn calls inside that transaction, then write the migration version
(insert or update your migrations table / schema version record) inside the same
transaction before committing; ensure any error rolls back so re-running
migrations won't see a half-applied state.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Thanks for catching this. This is a pre-existing issue not introduced by this PR, so I've created a separate issue to track it: #43

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@coji, thanks for the context! Good call on tracking it separately in #43 since it's a pre-existing pattern across all migrations. I'll keep an eye out for it in future reviews.


🧠 Learnings used
Learnt from: CR
Repo: coji/durably PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-04T13:25:17.638Z
Learning: Database schema consists of four tables: `durably_runs`, `durably_steps`, `durably_logs`, `durably_schema_versions` with specified key fields

Learnt from: CR
Repo: coji/durably PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-04T13:25:17.638Z
Learning: Applies to **/*.{ts,tsx} : Use top-level `await` for async initialization (e.g., `await durably.migrate()`). Do not wrap in async IIFE or Promise chains

Comment thread packages/durably/src/worker.ts
Comment thread website/api/durably-react/client.md Outdated
coji and others added 3 commits March 5, 2026 07:32
… type

Server /runs and /run endpoints now return ClientRun (excluding heartbeatAt,
idempotencyKey, concurrencyKey, updatedAt). Added toClientRun() projection
helper exported from core. durably-react ClientRun now re-exports from core.
Also fixed confusing input.input naming in subscribe tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update types.md to reflect ClientRun excluding internal fields, add
currentStepIndex/stepCount fields. Add ClientRun and toClientRun to
quick reference. Note core re-export in react llms.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace .payload with .input and RunRecord with ClientRun in all
example dashboard components.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coji coji merged commit 09ee1cc into main Mar 4, 2026
4 checks passed
@coji coji deleted the refactor/unify-run-types branch March 5, 2026 12:14
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.

Refactor: deduplicate RunRecord and ClientRun types

1 participant