Skip to content

Waitpoint token callback URLs #2025

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

Merged
merged 57 commits into from
May 7, 2025
Merged

Waitpoint token callback URLs #2025

merged 57 commits into from
May 7, 2025

Conversation

matt-aitken
Copy link
Member

@matt-aitken matt-aitken commented May 5, 2025

When you create a Waitpoint token we now give you back a URL. You can do an HTTP POST request to it and it will complete the waitpoint with the data you send.

This allows you to start some work on another API (or one of your own services) and continue the run when the callback URL we give you is hit with the result.

In this example we start a Replicate prediction and continue the run when the prediction is complete.

import { wait } from "@trigger.dev/sdk";

const token = await wait.createToken({
  timeout: "10m",
});

const call = await replicate.predictions.create({
  version: "27b93a2413e7f36cd83da926f3656280b2931564ff050bf9575f1fdf9bcd7478",
  input: {
    prompt: "A painting of a cat by Andy Warhol",
  },
  // pass the provided URL to Replicate's webhook, so they can "callback"
  webhook: token.url,
  webhook_events_filter: ["completed"],
});

const prediction = await wait.forToken<Prediction>(token).unwrap();
// unwrap() throws a timeout error or returns the result   👆

Security

The URL include the waitpoint friendlyId and a HMAC of the waitpoint.id + the environment API key. E.g.

http://localhost:3030/api/v1/waitpoints/tokens/waitpoint_cmadrg9ir0005o27cexiglxck/callback/2d746e4ab2586ca11b8e78b4eea9c5c89cc03ec3fa35515ade65ca91a794f496

This makes these URLs safe as they're unguessable and they don't leak any private information.

Summary by CodeRabbit

  • New Features

    • Added a secure HTTP callback URL to waitpoint tokens, enabling completion via a POST request to the provided URL.
    • The callback URL is now visible in the web app for manual waitpoints and in API responses.
    • Introduced a new API endpoint for completing waitpoints using the callback URL.
    • Extended SDK and documentation to support and explain the callback URL and its usage, including a new .unwrap() method for easier result handling.
  • Bug Fixes

    • Corrected minor documentation typos and formatting.
  • Chores

    • Updated dependencies and improved import organization in various packages.
    • Enhanced security by adding callback URL patterns to the API rate limiter whitelist.

Copy link

changeset-bot bot commented May 5, 2025

🦋 Changeset detected

Latest commit: d4b7135

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

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

Copy link
Contributor

coderabbitai bot commented May 5, 2025

Walkthrough

This change introduces secure HTTP callback URLs for waitpoint tokens, allowing external systems to complete waitpoints via POST requests. The callback URL is now generated and included in token objects, exposed in API responses, UI tables, and documentation. Supporting logic for URL generation, verification, and handling of callback requests is implemented, with related types and presenter classes updated accordingly.

Changes

Files / Areas Changed Change Summary
apps/webapp/app/services/httpCallback.server.ts New module for generating and verifying secure HTTP callback URLs using HMAC with waitpoint ID and API key. Exports generateHttpCallbackUrl and verifyHttpCallbackHash.
apps/webapp/app/presenters/v3/WaitpointListPresenter.server.ts, ApiWaitpointListPresenter.server.ts, WaitpointPresenter.server.ts, ApiWaitpointPresenter.server.ts Presenter classes and types renamed from "TokenList" to "List". Signatures updated to require apiKey. Logic extended to generate and include callback url for waitpoints/tokens.
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens/route.tsx Table updated to display the new callback URL for each token using ClipboardField. Presenter reference updated.
apps/webapp/app/components/runs/v3/WaitpointDetails.tsx Waitpoint details table now conditionally shows the callback URL row for manual waitpoints, using ClipboardField.
apps/webapp/app/components/runs/v3/RunIcon.tsx Added icon mapping for "wait-token" and "function" task types.
apps/webapp/app/routes/api.v1.waitpoints.tokens.ts API loader and action updated to use new presenter and include callback URL in responses.
apps/webapp/app/routes/api.v1.waitpoints.tokens.$waitpointFriendlyId.callback.$hash.ts New API route: Handles POST requests to complete a waitpoint via callback URL. Validates hash, parses body, marks waitpoint as complete, and returns JSON response.
apps/webapp/app/services/apiRateLimit.server.ts Added callback URL pattern to API rate limiter whitelist.
packages/core/src/v3/schemas/api.ts Zod schemas for waitpoint token item and creation response extended with required url property.
packages/core/src/v3/apiClient/index.ts Unused imports removed and import order reorganized.
packages/trigger-sdk/src/v3/wait.ts WaitpointRetrievedToken type extended with url. Introduced ManualWaitpointPromise class with unwrap() for improved error handling. wait.forToken now returns this promise. Tracing spans include url. Documentation and example improved.
docs/wait-for-token.mdx, docs/wait.mdx Documentation updated: describes callback URL usage, .unwrap() method, and refines wait function docs.
references/hello-world/package.json Added openai, replicate, and zod dependencies.
references/hello-world/src/trigger/waits.ts New exported task waitHttpCallback demonstrates webhook callback usage with Replicate API and waitpoint tokens.
internal-packages/database/prisma/schema.prisma Fixed typo in comment for Waitpoint.tags.
.changeset/curvy-dogs-share.md Patch note: documents callback URL returned by wait.createToken().

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API
    participant Database
    participant Engine

    Client->>API: Request to create waitpoint token
    API->>Database: Store waitpoint token and retrieve API key
    API->>API: Generate callback URL (with HMAC hash)
    API-->>Client: Return token object with callback URL

    Note over Client,API: External service can POST to callback URL

    participant WebhookService

    WebhookService->>API: POST to /api/v1/waitpoints/tokens/{id}/callback/{hash}
    API->>Database: Lookup waitpoint and API key
    API->>API: Verify hash matches waitpoint ID and API key
    API->>Engine: Mark waitpoint as complete with POST body
    API-->>WebhookService: Return JSON success response
Loading

Poem

🐇
A token waits, a callback calls,
With secret hash, no one falls.
Now POST your JSON, complete the quest,
The waitpoint ends—your run is blessed!
Clipboard fields and docs anew,
Hopping forward, code and crew!

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@matt-aitken matt-aitken marked this pull request as ready for review May 6, 2025 15:01
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: 6

🔭 Outside diff range comments (1)
apps/webapp/app/presenters/v3/WaitpointListPresenter.server.ts (1)

69-84: 🛠️ Refactor suggestion

Cursor pagination uses unordered UUID – replace with createdAt for deterministic paging

ORDER BY w.id DESC together with w.id < ${cursor} assumes the id column is time-ordered, which isn’t true for CUID/UUID. Users can see duplicate / skipped rows when two waitpoints share the same timestamp but unordered ids.

Proposed fix (keeps the existing composite index suggested earlier):

-    ORDER BY
-      ${direction === "forward" ? Prisma.sql`w.id DESC` : Prisma.sql`w.id ASC`}
-    LIMIT ${pageSize + 1}`;
+    ORDER BY
+      ${direction === "forward"
+        ? Prisma.sql`w."createdAt" DESC, w.id DESC`
+        : Prisma.sql`w."createdAt" ASC,  w.id ASC`}
+    LIMIT ${pageSize + 1}`;

Then use the tuple (createdAt,id) for cursors.

🧹 Nitpick comments (17)
apps/webapp/app/assets/icons/HttpCallbackIcon.tsx (1)

1-22: Extend props and enhance accessibility
Consider extending the component to accept general SVG props (e.g., aria-label, role, event handlers) by typing its props as React.SVGProps<SVGSVGElement> and spreading ...props onto the <svg>. Also add aria-hidden="true" by default for decorative icons to improve accessibility and reusability.

-export function HttpCallbackIcon({ className }: { className?: string }) {
+import type { SVGProps } from "react";
+
+export function HttpCallbackIcon({ className, ...props }: SVGProps<SVGSVGElement>) {
   return (
     <svg
-      className={className}
+      className={className}
+      aria-hidden="true"
+      {...props}
       xmlns="http://www.w3.org/2000/svg"
       viewBox="0 0 24 24"
       fill="none"
apps/webapp/app/components/navigation/SideMenu.tsx (2)

84-84: Import HTTP callback icon.
Bringing in HttpCallbackIcon complements the existing icon set. Consider moving this import alongside other icon imports for grouping.


250-255: Add HTTP callbacks menu item.
Integration under "Waitpoints" looks correct. For consistency, change the label to title case ("HTTP Callbacks") and consider adding a data-action attribute for telemetry.

packages/core/src/v3/apiClient/index.ts (1)

794-810: Well-implemented API client method for HTTP callbacks

The createWaitpointHttpCallback method follows established patterns in the codebase:

  1. It uses the same parameter structure as similar methods
  2. It properly handles request options merging
  3. It correctly types the return value as an ApiPromise

This addition enables the SDK to create HTTP callback waitpoints via the API.

One minor note: the method accepts CreateWaitpointTokenRequestBody as its options parameter. While this likely works because both token and HTTP callback waitpoints share similar creation parameters, consider whether a more specific type like CreateWaitpointHttpCallbackRequestBody might be clearer in the future.

apps/webapp/app/presenters/v3/WaitpointListPresenter.server.ts (1)

257-259: Minor optimisation – use .count() instead of findFirst()

The sole purpose here is existence checking. findFirst fetches an entire row; count is marginally cheaper and expresses the intent better:

- const firstToken = await this._replica.waitpoint.findFirst({
+ const tokenCount = await this._replica.waitpoint.count({
     where: {
       environmentId: environment.id,
       resolver,
     },
   });
- if (firstToken) { hasAnyTokens = true; }
+ hasAnyTokens = tokenCount > 0;
references/hello-world/src/trigger/waits.ts (2)

155-176: Variable naming can cause confusion

Inside the task the identifier prediction now refers to the waitpoint result (wrapper with ok, output, etc.), not the Replicate response returned by replicate.predictions.create. Readers may assume otherwise.

Consider renaming to make intent crystal-clear:

- const prediction = await wait.forHttpCallback<Prediction>(...);
+ const predictionResult = await wait.forHttpCallback<Prediction>(...);

Same for result2 later on.


203-216: Handle timeout path to avoid silent failures

When result.ok is false, you log the error but still continue successfully. In production code you may want to throw so the task run fails and surfaces the timeout upstream.

if (!result.ok) {
  throw result.error; // re-throw so retries / alerts kick in
}

Up to you whether the example should model that.

docs/wait-for-http-callback.mdx (3)

18-26: Avoid variable shadowing in the example snippet

Inside the code sample you first declare

const replicate = new Replicate(...)

and a few lines later re-declare

export const replicate = task({...})

Using the same identifier for two different objects is confusing for readers and would be a compile-time error in a real file. Rename one of them (e.g. replicateClient / replicateTask) to keep the example self-contained and copy-paste-able.

Also applies to: 21-27


37-38: Likely typo: “Any Warhol” → “Andy Warhol”

The prompt string reads:

"A painting of a cat by Any Warhol"

unless this is deliberate word-play, it should say Andy Warhol.


8-11: Add comma for readability

“URL. When the callback URL is requested …”

Insert a comma after requested to match conventional punctuation:

… URL is requested, the run will …

Improves the flow and matches the LanguageTool hint.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~10-~10: A comma might be missing here.
Context: ...webhook) URL. When the callback URL is requested the run will continue where it left off...

(AI_EN_LECTOR_MISSING_PUNCTUATION_COMMA)

apps/webapp/app/routes/engine.v1.waitpoints.http-callback.ts (2)

52-72: tags array is built but never used

You populate the local tags array with the upserted tag records, yet it is not returned, logged, or passed to engine.createManualWaitpoint. This is probably vestigial from a previous iteration and may confuse future readers.

- let tags: { id: string; name: string }[] = [];
...
- if (tagRecord) {
-   tags.push(tagRecord);
- }

Either remove the accumulation entirely or pass the records where needed.


37-43: Consider using a dedicated request-body schema

The body is validated with CreateWaitpointTokenRequestBody, yet the resolver is hard-coded to "HTTP_CALLBACK". A separate CreateWaitpointHttpCallbackRequestBody (which already exists in @trigger.dev/core) would make intent explicit and prevent accidental omission of HTTP-callback-specific fields in the future.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.http-callbacks/route.tsx (2)

127-130: Link to the specific HTTP-callback docs page

The docs button currently points to /wait, which lands on the generic waitpoints page. Using the new page improves discoverability.

- <LinkButton ... to={docsPath("/wait")}>
+ <LinkButton ... to={docsPath("/wait-for-http-callback")}>

42-47: Unused import

v3WaitpointTokenPath is imported but not referenced in this file. Consider removing it to keep imports tidy.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.http-callbacks.$waitpointParam/route.tsx (1)

92-98: Redundant nested cn() call

cn already returns a string, so wrapping it in another cn is superfluous and just adds runtime overhead.

-    <div
-      className={cn(
-        cn(
-          "grid h-full max-h-full grid-rows-[2.5rem_1fr] overflow-hidden bg-background-bright",
-          waitpoint.status === "WAITING" && "grid-rows-[2.5rem_1fr_auto]"
-        )
-      )}
+    <div
+      className={cn(
+        "grid h-full max-h-full grid-rows-[2.5rem_1fr] overflow-hidden bg-background-bright",
+        waitpoint.status === "WAITING" && "grid-rows-[2.5rem_1fr_auto]"
+      )}
packages/trigger-sdk/src/v3/wait.ts (2)

381-402: Useless constructor in ManualWaitpointPromise

Extending Promise without additional state doesn’t require an explicit constructor – the default one suffices.
Removing it eliminates TS-lint (noUselessConstructor) noise and a few bytes.

-class ManualWaitpointPromise<TOutput> extends Promise<WaitpointTokenTypedResult<TOutput>> {
-  constructor(
-    executor: (
-      resolve: (
-        value: WaitpointTokenTypedResult<TOutput> | PromiseLike<WaitpointTokenTypedResult<TOutput>>
-      ) => void,
-      reject: (reason?: any) => void
-    ) => void
-  ) {
-    super(executor);
-  }
+class ManualWaitpointPromise<TOutput> extends Promise<WaitpointTokenTypedResult<TOutput>> {}
🧰 Tools
🪛 Biome (1.9.4)

[error] 382-391: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)


603-680: new Promise(async …) antipattern

Using an async executor in the Promise constructor can lead to unhandled rejections if an exception is thrown after the first await but before resolve/reject is called.
While the current try/catch mitigates most cases, refactoring to an async factory function avoids the pitfall entirely.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 053389d and c48b27a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (38)
  • apps/webapp/app/assets/icons/HttpCallbackIcon.tsx (1 hunks)
  • apps/webapp/app/components/BlankStatePanels.tsx (2 hunks)
  • apps/webapp/app/components/navigation/SideMenu.tsx (3 hunks)
  • apps/webapp/app/components/runs/v3/WaitpointDetails.tsx (4 hunks)
  • apps/webapp/app/presenters/v3/ApiWaitpointListPresenter.server.ts (4 hunks)
  • apps/webapp/app/presenters/v3/ApiWaitpointPresenter.server.ts (1 hunks)
  • apps/webapp/app/presenters/v3/WaitpointListPresenter.server.ts (9 hunks)
  • apps/webapp/app/presenters/v3/WaitpointPresenter.server.ts (4 hunks)
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.http-callbacks.$waitpointParam/route.tsx (1 hunks)
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.http-callbacks/route.tsx (1 hunks)
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens/route.tsx (2 hunks)
  • apps/webapp/app/routes/api.v1.waitpoints.http-callback.$waitpointFriendlyId.callback.ts (1 hunks)
  • apps/webapp/app/routes/api.v1.waitpoints.tokens.ts (2 hunks)
  • apps/webapp/app/routes/engine.v1.waitpoints.http-callback.ts (1 hunks)
  • apps/webapp/app/services/apiRateLimit.server.ts (1 hunks)
  • apps/webapp/app/utils/pathBuilder.ts (1 hunks)
  • docs/docs.json (1 hunks)
  • docs/wait-for-http-callback.mdx (1 hunks)
  • docs/wait-for-token.mdx (1 hunks)
  • docs/wait.mdx (1 hunks)
  • internal-packages/database/prisma/migrations/20250502154714_waitpoint_added_resolvers/migration.sql (1 hunks)
  • internal-packages/database/prisma/migrations/20250502155009_waitpoint_resolve_index_for_dashboard/migration.sql (1 hunks)
  • internal-packages/database/prisma/migrations/20250505164454_waitpoint_resolve_status_index/migration.sql (1 hunks)
  • internal-packages/database/prisma/migrations/20250505164720_waitpoint_drop_type_status_index/migration.sql (1 hunks)
  • internal-packages/database/prisma/migrations/20250505165445_waitpoint_drop_type_index/migration.sql (1 hunks)
  • internal-packages/database/prisma/schema.prisma (3 hunks)
  • internal-packages/run-engine/src/engine/index.ts (2 hunks)
  • internal-packages/run-engine/src/engine/systems/waitpointSystem.ts (2 hunks)
  • internal-packages/run-engine/src/engine/tests/checkpoints.test.ts (5 hunks)
  • internal-packages/run-engine/src/engine/tests/releaseConcurrency.test.ts (11 hunks)
  • internal-packages/run-engine/src/engine/tests/waitpoints.test.ts (8 hunks)
  • packages/core/src/v3/apiClient/index.ts (2 hunks)
  • packages/core/src/v3/schemas/api.ts (1 hunks)
  • packages/core/src/v3/types/index.ts (1 hunks)
  • packages/core/src/v3/types/waitpoints.ts (1 hunks)
  • packages/trigger-sdk/src/v3/wait.ts (4 hunks)
  • references/hello-world/package.json (1 hunks)
  • references/hello-world/src/trigger/waits.ts (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens/route.tsx (1)
apps/webapp/app/presenters/v3/WaitpointListPresenter.server.ts (1)
  • WaitpointListPresenter (69-301)
packages/core/src/v3/types/waitpoints.ts (1)
packages/core/src/v3/types/schemas.ts (2)
  • Schema (74-74)
  • inferSchemaOut (96-99)
apps/webapp/app/presenters/v3/WaitpointPresenter.server.ts (1)
packages/core/src/v3/isomorphic/friendlyId.ts (1)
  • WaitpointId (95-95)
apps/webapp/app/components/BlankStatePanels.tsx (4)
apps/webapp/app/components/primitives/InfoPanel.tsx (1)
  • InfoPanel (30-68)
apps/webapp/app/assets/icons/HttpCallbackIcon.tsx (1)
  • HttpCallbackIcon (1-22)
apps/webapp/app/components/primitives/Buttons.tsx (1)
  • LinkButton (333-399)
apps/webapp/app/utils/pathBuilder.ts (1)
  • docsPath (453-455)
references/hello-world/src/trigger/waits.ts (1)
packages/trigger-sdk/src/v3/wait.ts (1)
  • wait (404-836)
🪛 LanguageTool
docs/wait-for-http-callback.mdx

[uncategorized] ~10-~10: A comma might be missing here.
Context: ...webhook) URL. When the callback URL is requested the run will continue where it left off...

(AI_EN_LECTOR_MISSING_PUNCTUATION_COMMA)


[typographical] ~16-~16: It appears that a comma is missing.
Context: ... ## Usage In this example we create an image using Replicate. The...

(DURING_THAT_TIME_COMMA)


[uncategorized] ~138-~138: Possible missing comma found.
Context: ...rn the output of the token. If an error occurs it will throw an error.

(AI_HYDRA_LEO_MISSING_COMMA)

🪛 Biome (1.9.4)
packages/trigger-sdk/src/v3/wait.ts

[error] 382-391: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: units / 🧪 Unit Tests
🔇 Additional comments (57)
apps/webapp/app/presenters/v3/ApiWaitpointPresenter.server.ts (1)

6-6: Import path updated correctly
The waitpointStatusToApiStatus import has been updated to the new presenter file. Confirm that WaitpointListPresenter.server.ts exports this function and remove any residual imports or exports from the old module.

apps/webapp/app/services/apiRateLimit.server.ts (1)

62-62: Ensure rate-limit bypass is safe for callback endpoint
The HTTP callback route is whitelisted and bypasses rate limiting. Verify that the corresponding handler enforces proper validation (e.g., a secret token or signature) to prevent abuse by unauthenticated callers.

docs/docs.json (1)

50-56: Verify documentation page existence and naming
A new navigation entry for "wait-for-http-callback" was added. Confirm that the corresponding documentation file exists (e.g., wait-for-http-callback.md) and matches naming conventions so it renders correctly in the site.

internal-packages/database/prisma/migrations/20250505164720_waitpoint_drop_type_status_index/migration.sql (1)

1-2: Concurrent drop of obsolete index
Dropping the Waitpoint_environmentId_type_status_idx concurrently is correct to avoid table locks. The IF EXISTS guard makes this idempotent.

internal-packages/database/prisma/migrations/20250505165445_waitpoint_drop_type_index/migration.sql (1)

1-1: Correctly drop deprecated index concurrently.
Dropping Waitpoint_environmentId_type_createdAt_idx aligns the schema with the new resolver-based filters. Using CONCURRENTLY IF EXISTS avoids downtime by preventing table locks.

references/hello-world/package.json (1)

9-13: Add runtime dependencies for callback example.
Dependencies "openai", "replicate", and "zod" support the new waitHttpCallback SDK usage and input schema validation in the Hello World sample.

internal-packages/run-engine/src/engine/tests/releaseConcurrency.test.ts (1)

105-105: Add resolver parameter to createManualWaitpoint calls.
All test invocations now explicitly set resolver: "TOKEN" to conform with the updated method signature.

Also applies to: 158-158, 307-307, 361-361, 497-497, 677-677, 837-837, 1023-1023, 1197-1197, 1352-1352

internal-packages/database/prisma/migrations/20250505164454_waitpoint_resolve_status_index/migration.sql (1)

1-7: Add concurrent index for resolver & status.
Creating Waitpoint_environmentId_resolver_status_createdAt_idx with CONCURRENTLY IF NOT EXISTS optimizes queries filtering by environment, resolver, and status, ordered by creation time.

apps/webapp/app/components/navigation/SideMenu.tsx (1)

57-57: Import new HTTP callback route builder.
The v3WaitpointHttpCallbacksPath is required for the new menu link. Ensure the path builder exports match your route definitions.

packages/core/src/v3/types/index.ts (1)

10-10: Export added for new waitpoints functionality.

This change correctly exports the waitpoint types needed for the new HTTP callback functionality. This aligns with the PR objective of enabling workflows to pause until an HTTP request is received at a generated callback URL.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens/route.tsx (2)

39-39: Updated import to use the generalized WaitpointListPresenter.

This change appropriately updates the import to use the resolver-aware WaitpointListPresenter instead of the token-specific presenter, supporting the new resolver-based architecture.


87-92: Updated presenter instantiation with resolver type.

Good implementation of the resolver pattern. The resolver: "TOKEN" parameter properly identifies this as a token-based waitpoint, allowing the same presenter to be used for different resolver types including the new HTTP callbacks.

docs/wait.mdx (3)

7-7: Fixed import statement.

Added missing semicolon to the import statement, improving code consistency.


9-9: Corrected terminology.

Fixed the wording from "scheduled" to "schedule", improving clarity.


13-18: Improved table formatting and added new HTTP callback functionality.

The table formatting has been improved with better column widths and clearer descriptions. The new wait.forHttpCallback() function has been properly documented, clearly explaining its purpose.

internal-packages/database/prisma/migrations/20250502155009_waitpoint_resolve_index_for_dashboard/migration.sql (1)

1-2:

❓ Verification inconclusive

Added concurrent index for improved query performance.

This migration creates a concurrent index on the Waitpoint table covering environmentId, resolver, and createdAt columns, which will optimize dashboard queries. Using CREATE INDEX CONCURRENTLY is the correct approach to avoid locking issues in production, aligning with the PR objective of safely implementing database changes.


🏁 Script executed:

#!/bin/bash
# Verify this migration isn't duplicating existing indexes

# Search for existing similar indexes on the Waitpoint table
rg -A 3 "CREATE.*INDEX.*Waitpoint.*environmentId.*resolver" --glob="*.sql"

Length of output: 922


Confirm index necessity to avoid duplication

This migration adds a concurrent index on (environmentId, resolver, createdAt), but there’s an existing index Waitpoint_environmentId_resolver_status_createdAt_idx on (environmentId, resolver, status, createdAt). Since the existing index already prefixes on the same columns, please confirm that the new index is required for queries that don’t filter by status, or consider consolidating/dropping one to avoid redundancy.

• internal-packages/database/prisma/migrations/20250505164454_waitpoint_resolve_status_index/migration.sql
• internal-packages/database/prisma/migrations/20250502155009_waitpoint_resolve_index_for_dashboard/migration.sql

internal-packages/run-engine/src/engine/tests/checkpoints.test.ts (1)

94-94: Correctly updated test cases with the new required resolver parameter.

The changes properly adapt all test cases to include the new required resolver: "TOKEN" parameter in calls to engine.createManualWaitpoint(). This ensures the tests remain compatible with the updated method signature while maintaining the original test semantics.

Also applies to: 353-353, 404-404, 557-557

docs/wait-for-token.mdx (1)

273-283: Great documentation for the new unwrap() method.

The added documentation clearly explains the purpose and benefits of the new .unwrap() method, providing a concise example that demonstrates how it simplifies error handling. This is a valuable addition that will help developers write cleaner code.

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

1013-1020: Well-structured schema for HTTP callback waitpoint responses.

The new CreateWaitpointHttpCallbackResponseBody schema properly defines the response structure for creating HTTP callback waitpoints, including the essential url field that external services will use to deliver results back to the system. The schema follows the existing patterns in the codebase and provides proper type safety.

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

9-12: Successfully adapted API route to the new resolver-based waitpoint system.

The changes correctly update this token-specific API endpoint to work with the more generic waitpoint system that supports multiple resolver types. The modifications include:

  1. Using the more generic presenter and search params classes
  2. Adding the explicit "TOKEN" resolver parameter to maintain the original functionality
  3. Properly updating type imports
  4. Adding the required resolver parameter to the engine call

These changes ensure the token API continues to function correctly while enabling the system to support additional waitpoint types like HTTP callbacks.

Also applies to: 24-25, 28-29, 78-78

internal-packages/run-engine/src/engine/tests/waitpoints.test.ts (6)

348-349: Implementation correctly adds required resolver parameter.

The addition of resolver: "TOKEN" aligns with the updated method signature in the WaitpointSystem that now requires explicitly specifying the resolver type. This change supports the new HTTP callbacks feature while maintaining backward compatibility for existing token-based waitpoints.


489-490: Implementation correctly includes resolver parameter for timeout test case.

The resolver parameter is consistently added to the waitpoint creation with timeout, maintaining the same pattern across test files.


612-613: Resolver parameter correctly added to batch test cases.

The addition of the resolver parameter to waitpoints used in concurrency testing ensures all test cases properly specify the resolver type.


907-908: Idempotency test case properly updated with resolver parameter.

The resolver parameter is correctly added to the waitpoint with idempotency key test, ensuring all test scenarios continue to function with the new resolver requirement.


1060-1061: TTL idempotency test cases consistently updated.

Both waitpoint creation calls in the TTL idempotency test are properly updated with the resolver parameter, maintaining consistency across the test suite.

Also applies to: 1071-1072


1227-1228: Concurrency test case updated with resolver parameter.

The addition of the resolver parameter to the concurrency test case ensures the test continues to function with the updated method signature.

internal-packages/database/prisma/migrations/20250502154714_waitpoint_added_resolvers/migration.sql (1)

1-6: Migration correctly implements waitpoint resolver support.

This migration properly creates the necessary database schema changes to support multiple waitpoint resolver types:

  1. Creates a new enum type with the three resolver values needed (ENGINE, TOKEN, HTTP_CALLBACK)
  2. Adds a non-nullable column with a default value, which is a safe operation that won't lock tables during migration

The approach of using an enum type ensures type safety at the database level and aligns well with the PR objective of supporting HTTP callbacks as a new resolver type.

apps/webapp/app/components/BlankStatePanels.tsx (2)

39-39: Appropriate icon import for HTTP callbacks.

The HttpCallbackIcon import is correctly added to support the new HTTP callbacks UI component.


435-461: Well-designed blank state component for HTTP callbacks.

This component follows the established pattern for blank state panels while providing clear explanation of HTTP callbacks:

  • Uses consistent styling with other blank state panels
  • Provides concise explanation of the HTTP callback feature
  • Includes appropriate documentation link
  • Uses distinct teal color theme to differentiate from token waitpoints

The explanatory text clearly communicates the purpose and use case for HTTP callbacks, helping users understand when to use this feature.

internal-packages/run-engine/src/engine/systems/waitpointSystem.ts (2)

232-233: Properly typed resolver parameter added to method signature.

The addition of the required resolver parameter with proper typing ("TOKEN" | "HTTP_CALLBACK") ensures type safety and makes the API contract explicit. This change is foundational for supporting different waitpoint resolution mechanisms.

Also applies to: 240-241


290-291: Resolver parameter correctly included in database operation.

The resolver parameter is properly included in the Prisma upsert operation when creating the waitpoint, ensuring the resolver type is stored in the database. This change aligns with the database migration that added the resolver column.

internal-packages/run-engine/src/engine/index.ts (2)

836-853: Good implementation of the resolver parameter!

The addition of the resolver parameter to the createManualWaitpoint method appropriately distinguishes between different waitpoint resolution mechanisms. This change aligns well with the new HTTP callback functionality described in the PR objectives.


854-863: Method implementation correctly passes the resolver parameter

The resolver parameter is properly passed through to the waitpoint system, ensuring consistent behavior throughout the codebase.

apps/webapp/app/components/runs/v3/WaitpointDetails.tsx (6)

10-14: Path builder imports support both resolver types

The import of both token and HTTP callback path builders enables proper navigation for different waitpoint types.


18-22: Good UI component imports for new functionality

The additional imports for CopyableText, ClipboardField, WaitpointResolver, and icons provide the necessary UI elements for displaying and interacting with HTTP callback waitpoints.


51-59: Well-implemented conditional routing based on resolver type

The ternary operator effectively routes to the appropriate path based on the waitpoint resolver type, ensuring users navigate to the correct detail view.


68-73: Good addition of the resolver type display

The addition of a dedicated property item for showing the waitpoint resolver type improves clarity for users.


74-81: Well-implemented conditional display of callback URL

The conditional rendering of the callback URL with a copy function provides excellent UX for HTTP callback waitpoints, allowing users to easily copy the URL for use with external services.


161-178: Great implementation of the WaitpointResolverCombo component

This component effectively displays different resolver types with appropriate icons, enhancing visual distinction between TOKEN and HTTP_CALLBACK waitpoints. The consistent styling with existing components maintains UI coherence.

packages/core/src/v3/types/waitpoints.ts (1)

1-15: Clear type definitions for HTTP callbacks

The types defined here provide a solid foundation for HTTP callback waitpoints:

  1. HttpCallbackSchema reuses the existing Schema type, maintaining consistency
  2. HttpCallbackResultTypeFromSchema provides convenient type inference for output
  3. HttpCallbackResult uses a clear discriminated union pattern for success/error handling

These types align well with the overall system design and will provide good type safety for SDK users implementing HTTP callbacks.

apps/webapp/app/utils/pathBuilder.ts (2)

345-358: LGTM: Well-structured path function for HTTP callbacks listing

The v3WaitpointHttpCallbacksPath function follows the established pattern of other path builder functions in this file, correctly handling filter parameters and using the existing utilities like objectToSearchParams.


360-370: LGTM: Consistent implementation for specific HTTP callback path

The implementation properly builds on the list path function and adds the token ID parameter, maintaining consistency with other similar path builder functions like v3WaitpointTokenPath.

apps/webapp/app/presenters/v3/ApiWaitpointListPresenter.server.ts (3)

1-7: LGTM: Updated imports for the new resolver type support

The imports have been correctly updated to include WaitpointResolver from the database package and reference the renamed presenter.


9-60: LGTM: No changes to search parameter handling

This section maintains the existing search parameter handling logic, which is appropriate since the resolver type filtering is handled separately.


62-132: LGTM: Added resolver parameter to support filtering by resolver type

The resolver parameter has been correctly added to the call method and is properly passed to the WaitpointListPresenter, enabling filtering waitpoints by their resolution mechanism.

apps/webapp/app/presenters/v3/WaitpointPresenter.server.ts (4)

5-7: LGTM: Updated imports to reflect renamed modules and added WaitpointId

The import changes correctly adapt to the renamed WaitpointListPresenter and add the necessary WaitpointId utility for generating callback URLs.


40-40: LGTM: Added resolver field to database query

The resolver field has been appropriately added to the database query to retrieve the resolver type information.


89-93: LGTM: Added resolver field and conditional callback URL to the returned object

The implementation correctly includes the resolver type in the returned object and conditionally adds the callback URL only when the resolver is of type "HTTP_CALLBACK".


112-116: LGTM: Well-implemented callback URL generator function

The generateWaitpointCallbackUrl function properly handles environment configuration to generate the full callback URL, using either API_ORIGIN or APP_ORIGIN as the base URL.

apps/webapp/app/routes/api.v1.waitpoints.http-callback.$waitpointFriendlyId.callback.ts (6)

13-15: LGTM: Clear parameter validation schema

The params schema correctly validates the waitpoint friendly ID parameter from the route.


17-24: LGTM: Proper HTTP method validation and ID conversion

The code correctly validates that only POST requests are allowed and appropriately converts the friendly ID to an internal ID format.


25-41: LGTM: Comprehensive waitpoint existence and status checks

The implementation properly verifies that the waitpoint exists and handles the case where it's already completed, returning appropriate HTTP status codes.


43-49: LGTM: Robust request body handling and serialization

The code appropriately processes the JSON request body and prepares it for storage, including potential packet export.


51-63: LGTM: Proper waitpoint completion with engine integration

The implementation correctly completes the waitpoint using the engine's API and returns a standardized success response.


64-67: LGTM: Appropriate error handling

The code properly catches any errors during processing, logs them, and returns a structured error response with the correct HTTP status code.

apps/webapp/app/presenters/v3/WaitpointListPresenter.server.ts (1)

270-271: Callback URL uses internal id, UI routes expect friendlyId

generateWaitpointCallbackUrl(token.id) passes the DB id. Most front-end & API routes (e.g. /api/v1/waitpoints/http-callback/:waitpointFriendlyId/callback) are keyed by friendlyId. Using the raw UUID will break deep-links and public-facing callbacks.

- callbackUrl: generateWaitpointCallbackUrl(token.id),
+ callbackUrl: generateWaitpointCallbackUrl(token.friendlyId),

Please verify the helper’s implementation – if it already expects a UUID this change will require adjusting route params correspondingly.

references/hello-world/src/trigger/waits.ts (1)

169-170: Timeout string exceeds Replicate SLA?

timeout: "10m" is generous. Replicate predictions for Stable-Diffusion-XL tend to finish in ~1-3 min; longer timeouts hold queue capacity longer. If this is an example, maybe reduce to "3m" to encourage best-practice.

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

♻️ Duplicate comments (1)
apps/webapp/app/routes/api.v1.waitpoints.http-callback.$waitpointFriendlyId.callback.$hash.ts (1)

87-90: Improve error handling to preserve intentional Response objects.

The current implementation treats all errors as unexpected and converts them to 500 responses, but should preserve any intentional Response objects that might be thrown.

-  logger.error("Failed to complete HTTP callback", { error });
-  throw json({ error: "Failed to complete HTTP callback" }, { status: 500 });
+  if (error instanceof Response) {
+    // Forward expected Remix responses untouched
+    throw error;
+  }
+
+  logger.error("Failed to complete HTTP callback", { error });
+  throw json({ error: "Failed to complete HTTP callback" }, { status: 500 });
🧹 Nitpick comments (2)
apps/webapp/app/routes/api.v1.waitpoints.http-callback.$waitpointFriendlyId.callback.$hash.ts (2)

65-66: Consider adding schema validation for the request body.

While the code gracefully handles JSON parsing errors, it doesn't validate that the request body matches an expected schema. Consider adding a Zod schema to validate the structure of the request body for more robust error handling.

 // If the request body is not valid JSON, return an empty object
 const body = await request.json().catch(() => ({}));
+
+// Define a schema for the expected body structure
+const bodySchema = z.object({
+  // Add expected fields here
+}).partial().default({});
+
+// Validate and transform the body using the schema
+const validatedBody = bodySchema.parse(body);

74-79: Consider checking and handling the result of the engine.completeWaitpoint call.

The result of engine.completeWaitpoint() is stored but never checked. It would be more robust to verify the completion was successful and handle any potential errors.

 const result = await engine.completeWaitpoint({
   id: waitpointId,
   output: finalData.data
     ? { type: finalData.dataType, value: finalData.data, isError: false }
     : undefined,
 });
+
+// Verify the waitpoint was completed successfully
+if (!result.success) {
+  logger.warn("Failed to complete waitpoint", { waitpointId, result });
+  return json({ error: "Failed to complete waitpoint" }, { status: 500 });
+}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 344dfde and fcbc275.

📒 Files selected for processing (1)
  • apps/webapp/app/routes/api.v1.waitpoints.http-callback.$waitpointFriendlyId.callback.$hash.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: units / 🧪 Unit Tests
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (6)
apps/webapp/app/routes/api.v1.waitpoints.http-callback.$waitpointFriendlyId.callback.$hash.ts (6)

1-14: Imports look good and cover all required dependencies.

The imports are well-structured and include all necessary dependencies for handling Remix actions, processing waitpoint data, database access, and security verification.


15-18: Parameter validation is properly implemented.

Good use of Zod schema to validate route parameters, ensuring type safety and preventing invalid inputs.


20-33: HTTP method and content size validation are well-implemented.

The endpoint correctly:

  1. Restricts to POST method with proper 405 response and Allow header
  2. Enforces Content-Length header presence (411 response if missing)
  3. Limits request body size based on environment configuration (413 response if too large)

These are good security practices for preventing abuse of the callback endpoint.


34-57: Security and error handling look good in this section.

The implementation:

  1. Properly parses and validates route parameters
  2. Correctly fetches the waitpoint from a replica database (good for read performance)
  3. Returns appropriate 404/401 errors for missing waitpoints or invalid hashes
  4. Uses return json() instead of throw json() as recommended in previous reviews

59-66: Waitpoint status check and body handling looks good.

The code properly:

  1. Returns early if the waitpoint is already completed, preventing duplicate processing
  2. Gracefully handles invalid JSON in the request body by falling back to an empty object

68-86: Waitpoint data processing and completion is implemented correctly.

The code:

  1. Properly processes and exports the request body data
  2. Correctly calls the engine to complete the waitpoint
  3. Returns an appropriate success response

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

🔭 Outside diff range comments (1)
apps/webapp/app/components/runs/v3/RunIcon.tsx (1)

51-52: ⚠️ Potential issue

Fix unreachable code in the existing component.

This line appears to be a statement that doesn't return anything, making it unreachable code after the return statements above. This should be fixed to correctly return the icon.

-    <InformationCircleIcon className={cn(className, "text-text-dimmed")} />;
+    return <InformationCircleIcon className={cn(className, "text-text-dimmed")} />;
♻️ Duplicate comments (2)
packages/trigger-sdk/src/v3/wait.ts (2)

480-501: Fix potential undefined access in unwrap() method

The unwrap() method assumes result.error.message is always defined when ok === false, which could cause an error if result.error is undefined or doesn't have a message property.

Apply this defensive approach to avoid potential errors:

  unwrap(): Promise<TOutput> {
    return this.then((result) => {
      if (result.ok) {
        return result.output;
      } else {
-        throw new WaitpointTimeoutError(result.error.message);
+        const message =
+          typeof result.error?.message === "string"
+            ? result.error.message
+            : "Waitpoint timed out";
+        throw new WaitpointTimeoutError(message);
      }
    });
  }
🧰 Tools
🪛 Biome (1.9.4)

[error] 481-490: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)


742-743: Same undefined-access risk for HTTP callback path

Similar to the issue in unwrap(), this code assumes data.message will always be defined.

Apply the same defensive approach:

-              const error = new WaitpointTimeoutError(data.message);
+              const error = new WaitpointTimeoutError(
+                typeof data?.message === "string" ? data.message : "Waitpoint timed out"
+              );
🧹 Nitpick comments (3)
apps/webapp/app/components/runs/v3/RunIcon.tsx (2)

83-84: Consider using consistent colors for all waitpoint types.

The wait-token case uses sky-500 color which differs from the teal-500 used by other wait types. For better visual consistency, consider using the same color for all waitpoint types.

-      return <WaitpointTokenIcon className={cn(className, "text-sky-500")} />;
+      return <WaitpointTokenIcon className={cn(className, "text-teal-500")} />;

84-85: Consider consolidating function-related cases.

The new function case is separated from related function hook cases (lines 101-112). Consider consolidating this with the existing function-related cases for better code organization.

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

480-490: Remove unnecessary constructor

The constructor is redundant as it simply passes arguments to the parent class without additional logic.

You can remove the constructor entirely:

class ManualWaitpointPromise<TOutput> extends Promise<WaitpointTokenTypedResult<TOutput>> {
-  constructor(
-    executor: (
-      resolve: (
-        value: WaitpointTokenTypedResult<TOutput> | PromiseLike<WaitpointTokenTypedResult<TOutput>>
-      ) => void,
-      reject: (reason?: any) => void
-    ) => void
-  ) {
-    super(executor);
-  }

  unwrap(): Promise<TOutput> {
    // ...
  }
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 481-490: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fcbc275 and 4e9c2ba.

📒 Files selected for processing (4)
  • .changeset/curvy-dogs-share.md (1 hunks)
  • apps/webapp/app/components/runs/v3/RunIcon.tsx (2 hunks)
  • packages/trigger-sdk/src/v3/wait.ts (5 hunks)
  • references/hello-world/src/trigger/waits.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .changeset/curvy-dogs-share.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • references/hello-world/src/trigger/waits.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/webapp/app/components/runs/v3/RunIcon.tsx (3)
apps/webapp/app/assets/icons/HttpCallbackIcon.tsx (1)
  • HttpCallbackIcon (1-22)
references/d3-chat/src/lib/utils.ts (1)
  • cn (4-6)
apps/webapp/app/assets/icons/WaitpointTokenIcon.tsx (1)
  • WaitpointTokenIcon (1-12)
🪛 Biome (1.9.4)
packages/trigger-sdk/src/v3/wait.ts

[error] 481-490: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)

⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: units / 🧪 Unit Tests
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (5)
apps/webapp/app/components/runs/v3/RunIcon.tsx (2)

22-23: New icon imports align with feature requirements.

The new imports for HttpCallbackIcon and WaitpointTokenIcon support the HTTP callback waitpoints feature described in the PR objectives.


80-82: HTTP callback waitpoint icon uses consistent styling.

The wait-http-callback case correctly uses the teal-500 color, matching the existing "wait" case styling for visual consistency.

packages/trigger-sdk/src/v3/wait.ts (3)

84-182: Well-implemented HTTP callback functionality with comprehensive documentation!

The new createHttpCallback function is well-designed, providing a clean API for integrating with external services that use webhooks. The tracing spans will ensure good observability, and the implementation follows established patterns in the codebase.


682-779: Nice refactor of forToken to utilize the new promise class

The refactoring of forToken to return a ManualWaitpointPromise provides a better developer experience with the .unwrap() method while maintaining the original functionality. The implementation includes proper error handling and tracing.


780-780: Correctly exposed new functionality in the exported API

Good job exporting the new createHttpCallback function through the wait object, making it available for users of the SDK.

@matt-aitken matt-aitken changed the title wait.forHttpCallback() wait.createHttpCallback() May 7, 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: 1

🧹 Nitpick comments (4)
docs/wait-for-http-callback.mdx (4)

16-16: Typographical: Add missing comma for clarity.

It appears a comma is missing after "In this example". Update as follows:

- In this example we create an image using Replicate.
+ In this example, we create an image using Replicate.
🧰 Tools
🪛 LanguageTool

[typographical] ~16-~16: It appears that a comma is missing.
Context: ... ## Usage In this example we create an image using Replicate. The...

(DURING_THAT_TIME_COMMA)


17-17: Use code formatting for technical terms.

Replace curly quotes around “webhook” with backticks for consistency in markdown:

- Their API accepts a “webhook”, which is an HTTP POST callback.
+ Their API accepts a `webhook`, which is an HTTP POST callback.

69-69: Enhance heading formatting for code clarity.

Consider wrapping method names in code formatting for consistency with other headings:

- ## unwrap()
+ ## `unwrap()`

103-103: Consistent heading capitalization.

Change "### returns" to title case to match other section headings:

- ### returns
+ ### Returns
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4e9c2ba and 2536c10.

📒 Files selected for processing (2)
  • docs/wait-for-http-callback.mdx (1 hunks)
  • docs/wait.mdx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/wait.mdx
🧰 Additional context used
🪛 LanguageTool
docs/wait-for-http-callback.mdx

[typographical] ~16-~16: It appears that a comma is missing.
Context: ... ## Usage In this example we create an image using Replicate. The...

(DURING_THAT_TIME_COMMA)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: units / 🧪 Unit Tests

Comment on lines 8 to 11
The `wait.createHttpCallback()` function gives you a callback URL and returns a token representing the waitpoint. You should call a third-party API and provide it with the callback URL so they can notify you when their work is done.

Then you can use `wait.forToken()` to pause the run until the callback URL is hit with a `POST` request.

Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify function naming consistency.

The documentation references wait.createHttpCallback(), but the PR title mentions wait.forHttpCallback(). Please ensure the function name in the docs matches the actual SDK method.

Run the following script to verify available methods in the SDK:


🏁 Script executed:

#!/bin/bash
# Verify function names in SDK wait implementation
rg -n "createHttpCallback" -n packages/trigger-sdk/src/v3/wait.ts
rg -n "forHttpCallback" -n packages/trigger-sdk/src/v3/wait.ts

Length of output: 309


Update PR title to use the correct SDK method name

The SDK only exposes wait.createHttpCallback(...)—there is no wait.forHttpCallback. Please update the PR title (and any other references) to use createHttpCallback for consistency.

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

♻️ Duplicate comments (1)
packages/trigger-sdk/src/v3/wait.ts (1)

419-427: unwrap() may throw with an undefined message
Same issue flagged previously: if result.error?.message is undefined, the thrown WaitpointTimeoutError will have an empty message, or result.error itself may be undefined.

Consider the earlier suggested guard:

-        throw new WaitpointTimeoutError(result.error.message);
+        const msg =
+          typeof result.error?.message === "string"
+            ? result.error.message
+            : "Waitpoint timed out";
+        throw new WaitpointTimeoutError(msg);
🧹 Nitpick comments (2)
apps/webapp/app/presenters/v3/ApiWaitpointListPresenter.server.ts (1)

1-2: Remove unused import

WaitpointResolver isn’t referenced in this file, so the import is dead code and may trip linting rules.

-import { type RunEngineVersion, type WaitpointResolver } from "@trigger.dev/database";
+import { type RunEngineVersion } from "@trigger.dev/database";
packages/trigger-sdk/src/v3/wait.ts (1)

407-417: Useless constructor – simplify the subclass

The constructor does nothing beyond delegating to super, triggering Biome’s noUselessConstructor warning. Removing it keeps the class lean.

-class ManualWaitpointPromise<TOutput> extends Promise<WaitpointTokenTypedResult<TOutput>> {
-  constructor(
-    executor: (
-      resolve: (
-        value: WaitpointTokenTypedResult<TOutput> | PromiseLike<WaitpointTokenTypedResult<TOutput>>
-      ) => void,
-      reject: (reason?: any) => void
-    ) => void
-  ) {
-    super(executor);
-  }
+class ManualWaitpointPromise<TOutput> extends Promise<WaitpointTokenTypedResult<TOutput>> {}
🧰 Tools
🪛 Biome (1.9.4)

[error] 408-417: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2536c10 and 9d01c88.

📒 Files selected for processing (15)
  • apps/webapp/app/components/navigation/SideMenu.tsx (1 hunks)
  • apps/webapp/app/components/runs/v3/RunIcon.tsx (2 hunks)
  • apps/webapp/app/components/runs/v3/WaitpointDetails.tsx (2 hunks)
  • apps/webapp/app/presenters/v3/ApiWaitpointListPresenter.server.ts (4 hunks)
  • apps/webapp/app/presenters/v3/WaitpointListPresenter.server.ts (7 hunks)
  • apps/webapp/app/presenters/v3/WaitpointPresenter.server.ts (4 hunks)
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens/route.tsx (5 hunks)
  • apps/webapp/app/routes/api.v1.waitpoints.tokens.$waitpointFriendlyId.callback.$hash.ts (1 hunks)
  • apps/webapp/app/routes/api.v1.waitpoints.tokens.ts (2 hunks)
  • apps/webapp/app/services/apiRateLimit.server.ts (1 hunks)
  • apps/webapp/app/services/httpCallback.server.ts (1 hunks)
  • docs/wait.mdx (1 hunks)
  • packages/core/src/v3/schemas/api.ts (2 hunks)
  • packages/trigger-sdk/src/v3/wait.ts (6 hunks)
  • references/hello-world/src/trigger/waits.ts (2 hunks)
✅ Files skipped from review due to trivial changes (2)
  • apps/webapp/app/services/apiRateLimit.server.ts
  • apps/webapp/app/services/httpCallback.server.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • docs/wait.mdx
  • apps/webapp/app/routes/api.v1.waitpoints.tokens.ts
  • apps/webapp/app/components/runs/v3/RunIcon.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.tokens/route.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/presenters/v3/WaitpointPresenter.server.ts
  • apps/webapp/app/presenters/v3/WaitpointListPresenter.server.ts
  • references/hello-world/src/trigger/waits.ts
  • packages/core/src/v3/schemas/api.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
apps/webapp/app/components/runs/v3/WaitpointDetails.tsx (1)
apps/webapp/app/components/primitives/ClipboardField.tsx (1)
  • ClipboardField (73-132)
apps/webapp/app/presenters/v3/ApiWaitpointListPresenter.server.ts (1)
apps/webapp/app/presenters/v3/WaitpointListPresenter.server.ts (2)
  • WaitpointListOptions (19-41)
  • WaitpointListPresenter (69-300)
🪛 Biome (1.9.4)
packages/trigger-sdk/src/v3/wait.ts

[error] 408-417: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)

⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: units / 🧪 Unit Tests
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)

Comment on lines 54 to 58
<Property.Item>
<Property.Label>Callback URL</Property.Label>
<Property.Value className="my-1">
<ClipboardField value={waitpoint.callbackUrl} variant={"secondary/small"} />
</Property.Value>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Guard against missing callbackUrl & consider masking secret portions

  1. ClipboardField renders whatever string it receives. If waitpoint.callbackUrl is undefined (e.g. resolver ≠ HTTP_CALLBACK or the presenter failed) the input will literally show the string "undefined", which is misleading.
  2. The URL contains an HMAC-style secret. Displaying it in full may be undesirable; ClipboardField already supports a secure prop to mask until focused.
-      <Property.Item>
-        <Property.Label>Callback URL</Property.Label>
-        <Property.Value className="my-1">
-          <ClipboardField value={waitpoint.callbackUrl} variant={"secondary/small"} />
-        </Property.Value>
-      </Property.Item>
+      {waitpoint.callbackUrl ? (
+        <Property.Item>
+          <Property.Label>Callback URL</Property.Label>
+          <Property.Value className="my-1">
+            {/* Mask the URL until the user focuses the field */}
+            <ClipboardField
+              value={waitpoint.callbackUrl}
+              secure
+              variant="secondary/small"
+            />
+          </Property.Value>
+        </Property.Item>
+      ) : null}

This prevents accidental leakage and avoids confusing "undefined" renders.

📝 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.

Suggested change
<Property.Item>
<Property.Label>Callback URL</Property.Label>
<Property.Value className="my-1">
<ClipboardField value={waitpoint.callbackUrl} variant={"secondary/small"} />
</Property.Value>
{waitpoint.callbackUrl ? (
<Property.Item>
<Property.Label>Callback URL</Property.Label>
<Property.Value className="my-1">
{/* Mask the URL until the user focuses the field */}
<ClipboardField
value={waitpoint.callbackUrl}
secure
variant="secondary/small"
/>
</Property.Value>
</Property.Item>
) : null}

@matt-aitken matt-aitken changed the title wait.createHttpCallback() Waitpoint token callback URLs May 7, 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: 0

🔭 Outside diff range comments (1)
packages/trigger-sdk/src/v3/wait.ts (1)

267-271: ⚠️ Potential issue

Avoid crash when data.message is undefined

data may be undefined, or not contain a message field. Safer construction:

-    error = new WaitpointTimeoutError(data.message);
+    const msg =
+      typeof (data as any)?.message === "string"
+        ? (data as any).message
+        : "Waitpoint timed out";
+    error = new WaitpointTimeoutError(msg);
♻️ Duplicate comments (1)
packages/trigger-sdk/src/v3/wait.ts (1)

421-428: Guard against missing error.message in .unwrap()
(See previous review – same issue)
Accessing result.error.message can throw if error or message is undefined. Use a fallback:

-        throw new WaitpointTimeoutError(result.error.message);
+        const msg =
+          typeof result.error?.message === "string"
+            ? result.error.message
+            : "Waitpoint timed out";
+        throw new WaitpointTimeoutError(msg);
🧹 Nitpick comments (4)
docs/wait-for-token.mdx (3)

57-78: Clarify external-service example & add missing replicate import

Great addition – the webhook example makes the callback flow much clearer.
To make the snippet copy-pasteable:

  1. Add import Replicate from "replicate"; (or the correct client import) so users know where replicate comes from.
  2. Consider adding a short note that the Replicate client must be initialised with an API key before use.

These small tweaks remove guess-work for readers and reduce the chance of “replicate is not defined” errors when they try the sample.


113-117: Minor punctuation – missing comma before “the output”

For readability, insert a comma after “body”:

-If there's no body the output will be an empty object `{}`.
+If there's no body, the output will be an empty object `{}`.

Applies to both occurrences in the createToken and listTokens property tables.

Also applies to: 373-377

🧰 Tools
🪛 LanguageTool

[uncategorized] ~116-~116: Possible missing comma found.
Context: ... the output of the token. If there's no body the output will be an empty object {}...

(AI_HYDRA_LEO_MISSING_COMMA)


305-315: Mention try/catch around .unwrap() for time-out handling

The .unwrap() helper is nice, but calling code still needs to handle the thrown WaitpointTimeoutError.
Adding a quick example:

try {
  const prediction = await wait.forToken<Prediction>(token).unwrap();
  // happy path
} catch (err) {
  // handle timeout
}

will reinforce the best-practice pattern.

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

410-419: Remove empty constructor – flagged by linter

ManualWaitpointPromise doesn’t add any logic in its constructor; the default inherited one is sufficient and keeps the class smaller:

-class ManualWaitpointPromise<TOutput> extends Promise<WaitpointTokenTypedResult<TOutput>> {
-  constructor(
-    executor: (
-      resolve: (
-        value: WaitpointTokenTypedResult<TOutput> | PromiseLike<WaitpointTokenTypedResult<TOutput>>
-      ) => void,
-      reject: (reason?: any) => void
-    ) => void
-  ) {
-    super(executor);
-  }
+class ManualWaitpointPromise<TOutput> extends Promise<WaitpointTokenTypedResult<TOutput>> {}
🧰 Tools
🪛 Biome (1.9.4)

[error] 410-419: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b24a47 and d4b7135.

📒 Files selected for processing (4)
  • docs/wait-for-token.mdx (6 hunks)
  • packages/core/src/v3/apiClient/index.ts (2 hunks)
  • packages/core/src/v3/schemas/api.ts (2 hunks)
  • packages/trigger-sdk/src/v3/wait.ts (9 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/core/src/v3/apiClient/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/v3/schemas/api.ts
🧰 Additional context used
🪛 Biome (1.9.4)
packages/trigger-sdk/src/v3/wait.ts

[error] 410-419: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)

🪛 LanguageTool
docs/wait-for-token.mdx

[uncategorized] ~116-~116: Possible missing comma found.
Context: ... the output of the token. If there's no body the output will be an empty object {}...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~376-~376: Possible missing comma found.
Context: ... the output of the token. If there's no body the output will be an empty object {}...

(AI_HYDRA_LEO_MISSING_COMMA)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (javascript-typescript)

@matt-aitken matt-aitken merged commit d23fa38 into main May 7, 2025
6 checks passed
@matt-aitken matt-aitken deleted the wait-for-http-callback branch May 7, 2025 18:55
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