-
Notifications
You must be signed in to change notification settings - Fork 158
Make resumeHook() accept a Hook object or string
#773
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make resumeHook() accept a Hook object or string
#773
Conversation
🦋 Changeset detectedLatest commit: 0551fe8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 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 |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📊 Benchmark Results
workflow with no steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express | Nitro workflow with 1 step💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) | Nitro workflow with 10 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express | Nitro Promise.all with 10 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Next.js (Turbopack) | Express Promise.all with 25 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Next.js (Turbopack) | Express Promise.race with 10 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express | Nitro Promise.race with 25 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Next.js (Turbopack) | Express Stream Benchmarks (includes TTFB metrics)workflow with stream💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express | Nitro SummaryFastest Framework by WorldWinner determined by most benchmark wins
Fastest World by FrameworkWinner determined by most benchmark wins
Column Definitions
Worlds:
|
🧪 E2E Test Results❌ Some tests failed Summary
❌ Failed Tests🌍 Community Worlds (17 failed)mongodb (1 failed):
redis (1 failed):
starter (14 failed):
turso (1 failed):
Details by Category✅ ▲ Vercel Production
✅ 💻 Local Development
✅ 📦 Local Production
✅ 🐘 Local Postgres
✅ 🪟 Windows
❌ 🌍 Community Worlds
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request enhances the resumeHook() function to accept either a token string (existing behavior) or a Hook object directly (new behavior), providing an optimization for resumeWebhook() by eliminating an unnecessary database lookup when the Hook object is already available.
Changes:
- Modified
resumeHook()parameter fromstringtostring | Hookwith conditional logic to handle both types - Updated
resumeWebhook()to pass the Hook object directly instead of its token - Updated JSDoc parameter documentation to reflect the new signature
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| packages/core/src/runtime/resume-hook.ts | Modified resumeHook signature to accept Hook objects, added type checking logic, and updated resumeWebhook to utilize the optimization |
| .changeset/new-crabs-hope.md | Added changeset documenting the patch-level API enhancement |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const hook = | ||
| typeof tokenOrHook === 'string' | ||
| ? await getHookByToken(tokenOrHook) | ||
| : tokenOrHook; |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a Hook object is passed directly to resumeHook, it bypasses the metadata hydration logic that exists in getHookByToken(). The getHookByToken function hydrates the metadata property using hydrateStepArguments if it was set from within the workflow run. This could lead to bugs when the hook's metadata is used elsewhere in the workflow execution, as it would remain in its serialized/dehydrated form rather than being properly deserialized. Consider either: 1) documenting that callers must ensure the Hook object has already been processed through getHookByToken, or 2) adding metadata hydration logic here to handle Hook objects that haven't been hydrated yet.
| : tokenOrHook; | |
| : (() => { | |
| const directHook = tokenOrHook; | |
| if (typeof directHook.metadata !== 'undefined') { | |
| directHook.metadata = hydrateStepArguments( | |
| directHook.metadata as any, | |
| [], | |
| directHook.runId | |
| ); | |
| } | |
| return directHook; | |
| })(); |
| export async function resumeHook<T = any>( | ||
| token: string, | ||
| tokenOrHook: string | Hook, | ||
| payload: T | ||
| ): Promise<Hook> { | ||
| return await waitedUntil(() => { | ||
| return trace('HOOK.resume', async (span) => { | ||
| const world = getWorld(); | ||
|
|
||
| try { | ||
| const hook = await getHookByToken(token); | ||
| const hook = | ||
| typeof tokenOrHook === 'string' | ||
| ? await getHookByToken(tokenOrHook) | ||
| : tokenOrHook; |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new functionality allowing resumeHook to accept a Hook object lacks test coverage. Given that the codebase has comprehensive test coverage for similar runtime functions (e.g., start.test.ts), tests should be added to verify: 1) that resumeHook correctly handles Hook objects, 2) that the hook's token is properly extracted for telemetry attributes, and 3) that the optimization in resumeWebhook works as expected. This is especially important because of the metadata hydration concern.
| const hook = | ||
| typeof tokenOrHook === 'string' | ||
| ? await getHookByToken(tokenOrHook) | ||
| : tokenOrHook; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const hook = | |
| typeof tokenOrHook === 'string' | |
| ? await getHookByToken(tokenOrHook) | |
| : tokenOrHook; | |
| let hook: Hook; | |
| if (typeof tokenOrHook === 'string') { | |
| hook = await getHookByToken(tokenOrHook); | |
| } else { | |
| hook = tokenOrHook; | |
| // Hydrate the metadata if it was set from within the workflow run | |
| // (same as getHookByToken does for consistency) | |
| if (typeof hook.metadata !== 'undefined') { | |
| hook.metadata = hydrateStepArguments(hook.metadata as any, [], hook.runId); | |
| } | |
| } |
When a Hook object is passed directly to resumeHook(), its metadata is not hydrated via hydrateStepArguments() like it is when a token string is passed, causing inconsistent behavior.
pranaygp
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.

Why make this change?
Optimization for
resumeWebhook().This change improves efficiency in cases where the caller already has the
Hookobject, eliminating the need to perform an additional database lookup by token. It maintains backward compatibility while providing a more flexible API.