Skip to content

Commit acd351d

Browse files
committed
Moved resumeTokens to just be wait functions 🥳
1 parent 44e3158 commit acd351d

File tree

12 files changed

+258
-83
lines changed

12 files changed

+258
-83
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
export function WaitTokenIcon({ className }: { className?: string }) {
2+
return (
3+
<svg className={className} viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
4+
<g clip-path="url(#clip0_16172_85184)">
5+
<path
6+
d="M13.3335 8L6.66683 8"
7+
stroke="currentColor"
8+
stroke-width="1.33333"
9+
stroke-linecap="round"
10+
stroke-linejoin="round"
11+
/>
12+
<path
13+
d="M13.3335 8L10.6668 10.6667"
14+
stroke="currentColor"
15+
stroke-width="1.33333"
16+
stroke-linecap="round"
17+
stroke-linejoin="round"
18+
/>
19+
<path
20+
d="M13.3335 7.99992L10.6668 5.33325"
21+
stroke="currentColor"
22+
stroke-width="1.33333"
23+
stroke-linecap="round"
24+
stroke-linejoin="round"
25+
/>
26+
<path
27+
d="M3.6665 2.66675L3.6665 13.3334"
28+
stroke="currentColor"
29+
stroke-width="1.33333"
30+
stroke-linecap="round"
31+
stroke-linejoin="round"
32+
/>
33+
</g>
34+
<defs>
35+
<clipPath id="clip0_16172_85184">
36+
<rect width="16" height="16" fill="currentColor" />
37+
</clipPath>
38+
</defs>
39+
</svg>
40+
);
41+
}

‎apps/webapp/app/components/runs/v3/RunIcon.tsx‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { TaskIcon } from "~/assets/icons/TaskIcon";
1010
import { TaskCachedIcon } from "~/assets/icons/TaskCachedIcon";
1111
import { NamedIcon } from "~/components/primitives/NamedIcon";
1212
import { cn } from "~/utils/cn";
13+
import { WaitTokenIcon } from "~/assets/icons/WaitTokenIcon";
1314

1415
type TaskIconProps = {
1516
name: string | undefined;
@@ -54,6 +55,8 @@ export function RunIcon({ name, className, spanName }: TaskIconProps) {
5455
return <Squares2X2Icon className={cn(className, "text-text-dimmed")} />;
5556
case "tag":
5657
return <TagIcon className={cn(className, "text-text-dimmed")} />;
58+
case "wait-token":
59+
return <WaitTokenIcon className={cn(className, "text-text-dimmed")} />;
5760
//log levels
5861
case "debug":
5962
case "log":
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { json } from "@remix-run/server-runtime";
2+
import {
3+
CompleteWaitpointTokenRequestBody,
4+
CompleteWaitpointTokenResponseBody,
5+
conditionallyExportPacket,
6+
CreateWaitpointTokenResponseBody,
7+
stringifyIO,
8+
} from "@trigger.dev/core/v3";
9+
import { WaitpointId } from "@trigger.dev/core/v3/apps";
10+
import { z } from "zod";
11+
import { $replica } from "~/db.server";
12+
import { logger } from "~/services/logger.server";
13+
import { createActionApiRoute } from "~/services/routeBuilders/apiBuilder.server";
14+
import { parseDelay } from "~/utils/delays";
15+
import { resolveIdempotencyKeyTTL } from "~/utils/idempotencyKeys.server";
16+
import { engine } from "~/v3/runEngine.server";
17+
18+
const { action } = createActionApiRoute(
19+
{
20+
params: z.object({
21+
waitpointFriendlyId: z.string(),
22+
}),
23+
body: CompleteWaitpointTokenRequestBody,
24+
maxContentLength: 1024 * 10, // 10KB
25+
method: "POST",
26+
},
27+
async ({ authentication, body, params }) => {
28+
// Resume tokens are actually just waitpoints
29+
const waitpointId = WaitpointId.toId(params.waitpointFriendlyId);
30+
31+
try {
32+
const stringifiedData = await stringifyIO(body.data);
33+
const finalData = await conditionallyExportPacket(
34+
stringifiedData,
35+
`${waitpointId}/waitpoint/token`
36+
);
37+
38+
//check permissions
39+
const waitpoint = await $replica.waitpoint.findFirst({
40+
where: {
41+
id: waitpointId,
42+
environmentId: authentication.environment.id,
43+
},
44+
});
45+
46+
if (!waitpoint) {
47+
throw json({ error: "Waitpoint not found" }, { status: 404 });
48+
}
49+
50+
const result = await engine.completeWaitpoint({
51+
id: waitpointId,
52+
output: finalData.data
53+
? { type: finalData.dataType, value: finalData.data, isError: false }
54+
: undefined,
55+
});
56+
57+
return json<CompleteWaitpointTokenResponseBody>(
58+
{
59+
success: true,
60+
},
61+
{ status: 200 }
62+
);
63+
} catch (error) {
64+
logger.error("Failed to complete waitpoint token", { error });
65+
throw json({ error: "Failed to complete waitpoint token" }, { status: 500 });
66+
}
67+
}
68+
);
69+
70+
export { action };

apps/webapp/app/routes/api.v1.waitpoints.ts renamed to apps/webapp/app/routes/api.v1.waitpoints.tokens.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import { json } from "@remix-run/server-runtime";
2-
import { CreateWaitpointRequestBody, CreateWaitpointResponseBody } from "@trigger.dev/core/v3";
3-
import { ResumeTokenId, WaitpointId } from "@trigger.dev/core/v3/apps";
2+
import {
3+
CreateWaitpointTokenRequestBody,
4+
CreateWaitpointTokenResponseBody,
5+
} from "@trigger.dev/core/v3";
6+
import { WaitpointId } from "@trigger.dev/core/v3/apps";
47
import { createActionApiRoute } from "~/services/routeBuilders/apiBuilder.server";
58
import { parseDelay } from "~/utils/delays";
69
import { resolveIdempotencyKeyTTL } from "~/utils/idempotencyKeys.server";
710
import { engine } from "~/v3/runEngine.server";
811

912
const { action } = createActionApiRoute(
1013
{
11-
body: CreateWaitpointRequestBody,
14+
body: CreateWaitpointTokenRequestBody,
1215
maxContentLength: 1024 * 10, // 10KB
1316
method: "POST",
1417
},
@@ -27,12 +30,9 @@ const { action } = createActionApiRoute(
2730
timeout,
2831
});
2932

30-
//result is a waitpoint but we want to make it look like a resume token
31-
const resumeTokenFriendlyId = ResumeTokenId.toFriendlyId(result.waitpoint.id);
32-
33-
return json<CreateWaitpointResponseBody>(
33+
return json<CreateWaitpointTokenResponseBody>(
3434
{
35-
id: resumeTokenFriendlyId,
35+
id: WaitpointId.toFriendlyId(result.waitpoint.id),
3636
isCached: result.isCached,
3737
},
3838
{ status: 200 }

‎packages/core/src/v3/apiClient/index.ts‎

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import {
77
BatchTriggerTaskV3RequestBody,
88
BatchTriggerTaskV3Response,
99
CanceledRunResponse,
10+
CompleteWaitpointTokenRequestBody,
11+
CompleteWaitpointTokenResponseBody,
1012
CreateEnvironmentVariableRequestBody,
1113
CreateScheduleOptions,
1214
CreateUploadPayloadUrlResponseBody,
13-
CreateWaitpointRequestBody,
14-
CreateWaitpointResponseBody,
15+
CreateWaitpointTokenRequestBody,
16+
CreateWaitpointTokenResponseBody,
1517
DeletedScheduleObject,
1618
EnvironmentVariableResponseBody,
1719
EnvironmentVariableValue,
@@ -637,10 +639,27 @@ export class ApiClient {
637639
);
638640
}
639641

640-
createResumeToken(options: CreateWaitpointRequestBody, requestOptions?: ZodFetchOptions) {
642+
createWaitpointToken(options: CreateWaitpointTokenRequestBody, requestOptions?: ZodFetchOptions) {
641643
return zodfetch(
642-
CreateWaitpointResponseBody,
643-
`${this.baseUrl}/api/v1/waitpoints`,
644+
CreateWaitpointTokenResponseBody,
645+
`${this.baseUrl}/api/v1/waitpoints/tokens`,
646+
{
647+
method: "POST",
648+
headers: this.#getHeaders(false),
649+
body: JSON.stringify(options),
650+
},
651+
mergeRequestOptions(this.defaultRequestOptions, requestOptions)
652+
);
653+
}
654+
655+
completeResumeToken(
656+
friendlyId: string,
657+
options: CompleteWaitpointTokenRequestBody,
658+
requestOptions?: ZodFetchOptions
659+
) {
660+
return zodfetch(
661+
CompleteWaitpointTokenResponseBody,
662+
`${this.baseUrl}/api/v1/waitpoints/tokens/${friendlyId}/complete`,
644663
{
645664
method: "POST",
646665
headers: this.#getHeaders(false),

‎packages/core/src/v3/apps/friendlyId.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,3 @@ export const RunId = new IdUtil("run");
9090
export const SnapshotId = new IdUtil("snapshot");
9191
export const WaitpointId = new IdUtil("waitpoint");
9292
export const BatchId = new IdUtil("batch");
93-
export const ResumeTokenId = new IdUtil("resumetoken");

‎packages/core/src/v3/schemas/api.ts‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,7 @@ export type SubscribeRealtimeStreamChunkRawShape = z.infer<
890890
export const TimePeriod = z.string().or(z.coerce.date());
891891
export type TimePeriod = z.infer<typeof TimePeriod>;
892892

893-
export const CreateWaitpointRequestBody = z.object({
893+
export const CreateWaitpointTokenRequestBody = z.object({
894894
/**
895895
* An optional idempotency key for the waitpoint.
896896
* If you use the same key twice (and the key hasn't expired), you will get the original waitpoint back.
@@ -910,13 +910,23 @@ export const CreateWaitpointRequestBody = z.object({
910910
*/
911911
timeout: TimePeriod.optional(),
912912
});
913-
export type CreateWaitpointRequestBody = z.infer<typeof CreateWaitpointRequestBody>;
913+
export type CreateWaitpointTokenRequestBody = z.infer<typeof CreateWaitpointTokenRequestBody>;
914914

915-
export const CreateWaitpointResponseBody = z.object({
915+
export const CreateWaitpointTokenResponseBody = z.object({
916916
id: z.string(),
917917
isCached: z.boolean(),
918918
});
919-
export type CreateWaitpointResponseBody = z.infer<typeof CreateWaitpointResponseBody>;
919+
export type CreateWaitpointTokenResponseBody = z.infer<typeof CreateWaitpointTokenResponseBody>;
920+
921+
export const CompleteWaitpointTokenRequestBody = z.object({
922+
data: z.any().nullish(),
923+
});
924+
export type CompleteWaitpointTokenRequestBody = z.infer<typeof CompleteWaitpointTokenRequestBody>;
925+
926+
export const CompleteWaitpointTokenResponseBody = z.object({
927+
success: z.literal(true),
928+
});
929+
export type CompleteWaitpointTokenResponseBody = z.infer<typeof CompleteWaitpointTokenResponseBody>;
920930

921931
export const WAITPOINT_TIMEOUT_ERROR_CODE = "TRIGGER_WAITPOINT_TIMEOUT";
922932

‎packages/trigger-sdk/src/v3/index.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ export * from "./tags.js";
1212
export * from "./metadata.js";
1313
export * from "./timeout.js";
1414
export * from "./waitUntil.js";
15-
export * from "./resumeTokens.js";
1615
export type { Context };
1716

1817
import type { Context } from "./shared.js";

‎packages/trigger-sdk/src/v3/resumeTokens.ts‎

Lines changed: 0 additions & 44 deletions
This file was deleted.

‎packages/trigger-sdk/src/v3/wait.ts‎

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,75 @@
1-
import { SemanticInternalAttributes, accessoryAttributes, runtime } from "@trigger.dev/core/v3";
1+
import {
2+
SemanticInternalAttributes,
3+
accessoryAttributes,
4+
runtime,
5+
apiClientManager,
6+
ApiPromise,
7+
ApiRequestOptions,
8+
conditionallyExportPacket,
9+
CreateWaitpointTokenRequestBody,
10+
CreateWaitpointTokenResponseBody,
11+
mergeRequestOptions,
12+
stringifyIO,
13+
CompleteWaitpointTokenResponseBody,
14+
} from "@trigger.dev/core/v3";
215
import { tracer } from "./tracer.js";
316

17+
function createToken(
18+
options?: CreateWaitpointTokenRequestBody,
19+
requestOptions?: ApiRequestOptions
20+
): ApiPromise<CreateWaitpointTokenResponseBody> {
21+
const apiClient = apiClientManager.clientOrThrow();
22+
23+
const $requestOptions = mergeRequestOptions(
24+
{
25+
tracer,
26+
name: "wait.createToken()",
27+
icon: "wait-token",
28+
attributes: {
29+
idempotencyKey: options?.idempotencyKey,
30+
idempotencyKeyTTL: options?.idempotencyKeyTTL,
31+
timeout: options?.timeout
32+
? typeof options.timeout === "string"
33+
? options.timeout
34+
: options.timeout.toISOString()
35+
: undefined,
36+
},
37+
onResponseBody: (body: CreateWaitpointTokenResponseBody, span) => {
38+
span.setAttribute("id", body.id);
39+
span.setAttribute("isCached", body.isCached);
40+
},
41+
},
42+
requestOptions
43+
);
44+
45+
return apiClient.createWaitpointToken(options ?? {}, $requestOptions);
46+
}
47+
48+
async function completeToken<T>(
49+
token: { id: string },
50+
data: T,
51+
requestOptions?: ApiRequestOptions
52+
) {
53+
const apiClient = apiClientManager.clientOrThrow();
54+
55+
const $requestOptions = mergeRequestOptions(
56+
{
57+
tracer,
58+
name: "wait.completeToken()",
59+
icon: "wait-token",
60+
attributes: {
61+
id: token.id,
62+
},
63+
onResponseBody: (body: CompleteWaitpointTokenResponseBody, span) => {
64+
span.setAttribute("success", body.success);
65+
},
66+
},
67+
requestOptions
68+
);
69+
70+
return apiClient.completeResumeToken(token.id, { data }, $requestOptions);
71+
}
72+
473
export type WaitOptions =
574
| {
675
seconds: number;
@@ -80,6 +149,8 @@ export const wait = {
80149
}
81150
);
82151
},
152+
createToken,
153+
completeToken,
83154
};
84155

85156
function nameForWaitOptions(options: WaitOptions): string {

0 commit comments

Comments
 (0)