testdriverai 6.0.28 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/trigger.basic.mdc +190 -0
- package/.github/instructions/trigger-basic.instructions.md +188 -0
- package/CLAUDE.md +188 -0
- package/agent/index.js +53 -25
- package/agent/interface.js +36 -0
- package/agent/lib/censorship.js +15 -10
- package/agent/lib/generator.js +2 -2
- package/agent/lib/sandbox.js +1 -1
- package/agent/lib/sdk.js +2 -1
- package/index.html +147 -0
- package/interfaces/cli/commands/generate.js +3 -0
- package/interfaces/cli/lib/base.js +1 -1
- package/interfaces/cli/utils/factory.js +16 -7
- package/package.json +3 -1
- package/static-analysis.datadog.yml +10 -0
- package/testdriver/examples/playwright/postrun.yaml +44 -0
- package/testdriver/examples/playwright/provision.yaml +43 -0
- package/testdriver/examples/web/lifecycle/postrun.yaml +7 -0
- package/testdriver/examples/web/lifecycle/{provision.yaml → prerun.yaml} +6 -0
- package/testdriver/generate/test-locked-out-user-login.yaml +37 -0
- package/testdriver/generate/test-standard-user-login.yaml +37 -0
- package/testdriver/generate/test-successful-logout.yaml +36 -0
- package/testdriver/lifecycle/postrun.yaml +2 -3
- package/testdriver/lifecycle/prerun.yaml +8 -2
- package/testdriver/lifecycle/provision.yaml +0 -12
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Only the most important rules for writing basic Trigger.dev tasks
|
|
3
|
+
globs: **/trigger/**/*.ts
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
# Trigger.dev Basic Tasks (v4)
|
|
7
|
+
|
|
8
|
+
**MUST use `@trigger.dev/sdk` (v4), NEVER `client.defineJob`**
|
|
9
|
+
|
|
10
|
+
## Basic Task
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { task } from "@trigger.dev/sdk";
|
|
14
|
+
|
|
15
|
+
export const processData = task({
|
|
16
|
+
id: "process-data",
|
|
17
|
+
retry: {
|
|
18
|
+
maxAttempts: 10,
|
|
19
|
+
factor: 1.8,
|
|
20
|
+
minTimeoutInMs: 500,
|
|
21
|
+
maxTimeoutInMs: 30_000,
|
|
22
|
+
randomize: false,
|
|
23
|
+
},
|
|
24
|
+
run: async (payload: { userId: string; data: any[] }) => {
|
|
25
|
+
// Task logic - runs for long time, no timeouts
|
|
26
|
+
console.log(`Processing ${payload.data.length} items for user ${payload.userId}`);
|
|
27
|
+
return { processed: payload.data.length };
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Schema Task (with validation)
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { schemaTask } from "@trigger.dev/sdk";
|
|
36
|
+
import { z } from "zod";
|
|
37
|
+
|
|
38
|
+
export const validatedTask = schemaTask({
|
|
39
|
+
id: "validated-task",
|
|
40
|
+
schema: z.object({
|
|
41
|
+
name: z.string(),
|
|
42
|
+
age: z.number(),
|
|
43
|
+
email: z.string().email(),
|
|
44
|
+
}),
|
|
45
|
+
run: async (payload) => {
|
|
46
|
+
// Payload is automatically validated and typed
|
|
47
|
+
return { message: `Hello ${payload.name}, age ${payload.age}` };
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Scheduled Task
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { schedules } from "@trigger.dev/sdk";
|
|
56
|
+
|
|
57
|
+
const dailyReport = schedules.task({
|
|
58
|
+
id: "daily-report",
|
|
59
|
+
cron: "0 9 * * *", // Daily at 9:00 AM UTC
|
|
60
|
+
// or with timezone: cron: { pattern: "0 9 * * *", timezone: "America/New_York" },
|
|
61
|
+
run: async (payload) => {
|
|
62
|
+
console.log("Scheduled run at:", payload.timestamp);
|
|
63
|
+
console.log("Last run was:", payload.lastTimestamp);
|
|
64
|
+
console.log("Next 5 runs:", payload.upcoming);
|
|
65
|
+
|
|
66
|
+
// Generate daily report logic
|
|
67
|
+
return { reportGenerated: true, date: payload.timestamp };
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Triggering Tasks
|
|
73
|
+
|
|
74
|
+
### From Backend Code
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { tasks } from "@trigger.dev/sdk";
|
|
78
|
+
import type { processData } from "./trigger/tasks";
|
|
79
|
+
|
|
80
|
+
// Single trigger
|
|
81
|
+
const handle = await tasks.trigger<typeof processData>("process-data", {
|
|
82
|
+
userId: "123",
|
|
83
|
+
data: [{ id: 1 }, { id: 2 }],
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Batch trigger
|
|
87
|
+
const batchHandle = await tasks.batchTrigger<typeof processData>("process-data", [
|
|
88
|
+
{ payload: { userId: "123", data: [{ id: 1 }] } },
|
|
89
|
+
{ payload: { userId: "456", data: [{ id: 2 }] } },
|
|
90
|
+
]);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### From Inside Tasks (with Result handling)
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
export const parentTask = task({
|
|
97
|
+
id: "parent-task",
|
|
98
|
+
run: async (payload) => {
|
|
99
|
+
// Trigger and continue
|
|
100
|
+
const handle = await childTask.trigger({ data: "value" });
|
|
101
|
+
|
|
102
|
+
// Trigger and wait - returns Result object, NOT task output
|
|
103
|
+
const result = await childTask.triggerAndWait({ data: "value" });
|
|
104
|
+
if (result.ok) {
|
|
105
|
+
console.log("Task output:", result.output); // Actual task return value
|
|
106
|
+
} else {
|
|
107
|
+
console.error("Task failed:", result.error);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Quick unwrap (throws on error)
|
|
111
|
+
const output = await childTask.triggerAndWait({ data: "value" }).unwrap();
|
|
112
|
+
|
|
113
|
+
// Batch trigger and wait
|
|
114
|
+
const results = await childTask.batchTriggerAndWait([
|
|
115
|
+
{ payload: { data: "item1" } },
|
|
116
|
+
{ payload: { data: "item2" } },
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
for (const run of results) {
|
|
120
|
+
if (run.ok) {
|
|
121
|
+
console.log("Success:", run.output);
|
|
122
|
+
} else {
|
|
123
|
+
console.log("Failed:", run.error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
export const childTask = task({
|
|
130
|
+
id: "child-task",
|
|
131
|
+
run: async (payload: { data: string }) => {
|
|
132
|
+
return { processed: payload.data };
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
> Never wrap triggerAndWait or batchTriggerAndWait calls in a Promise.all or Promise.allSettled as this is not supported in Trigger.dev tasks.
|
|
138
|
+
|
|
139
|
+
## Waits
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { task, wait } from "@trigger.dev/sdk";
|
|
143
|
+
|
|
144
|
+
export const taskWithWaits = task({
|
|
145
|
+
id: "task-with-waits",
|
|
146
|
+
run: async (payload) => {
|
|
147
|
+
console.log("Starting task");
|
|
148
|
+
|
|
149
|
+
// Wait for specific duration
|
|
150
|
+
await wait.for({ seconds: 30 });
|
|
151
|
+
await wait.for({ minutes: 5 });
|
|
152
|
+
await wait.for({ hours: 1 });
|
|
153
|
+
await wait.for({ days: 1 });
|
|
154
|
+
|
|
155
|
+
// Wait until specific date
|
|
156
|
+
await wait.until({ date: new Date("2024-12-25") });
|
|
157
|
+
|
|
158
|
+
// Wait for token (from external system)
|
|
159
|
+
await wait.forToken({
|
|
160
|
+
token: "user-approval-token",
|
|
161
|
+
timeoutInSeconds: 3600, // 1 hour timeout
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
console.log("All waits completed");
|
|
165
|
+
return { status: "completed" };
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
> Never wrap wait calls in a Promise.all or Promise.allSettled as this is not supported in Trigger.dev tasks.
|
|
171
|
+
|
|
172
|
+
## Key Points
|
|
173
|
+
|
|
174
|
+
- **Result vs Output**: `triggerAndWait()` returns a `Result` object with `ok`, `output`, `error` properties - NOT the direct task output
|
|
175
|
+
- **Type safety**: Use `import type` for task references when triggering from backend
|
|
176
|
+
- **Waits > 5 seconds**: Automatically checkpointed, don't count toward compute usage
|
|
177
|
+
|
|
178
|
+
## NEVER Use (v2 deprecated)
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
// BREAKS APPLICATION
|
|
182
|
+
client.defineJob({
|
|
183
|
+
id: "job-id",
|
|
184
|
+
run: async (payload, io) => {
|
|
185
|
+
/* ... */
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Use v4 SDK (`@trigger.dev/sdk`), check `result.ok` before accessing `result.output`
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: **/trigger/**/*.ts
|
|
3
|
+
---
|
|
4
|
+
# Trigger.dev Basic Tasks (v4)
|
|
5
|
+
|
|
6
|
+
**MUST use `@trigger.dev/sdk` (v4), NEVER `client.defineJob`**
|
|
7
|
+
|
|
8
|
+
## Basic Task
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { task } from "@trigger.dev/sdk";
|
|
12
|
+
|
|
13
|
+
export const processData = task({
|
|
14
|
+
id: "process-data",
|
|
15
|
+
retry: {
|
|
16
|
+
maxAttempts: 10,
|
|
17
|
+
factor: 1.8,
|
|
18
|
+
minTimeoutInMs: 500,
|
|
19
|
+
maxTimeoutInMs: 30_000,
|
|
20
|
+
randomize: false,
|
|
21
|
+
},
|
|
22
|
+
run: async (payload: { userId: string; data: any[] }) => {
|
|
23
|
+
// Task logic - runs for long time, no timeouts
|
|
24
|
+
console.log(`Processing ${payload.data.length} items for user ${payload.userId}`);
|
|
25
|
+
return { processed: payload.data.length };
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Schema Task (with validation)
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { schemaTask } from "@trigger.dev/sdk";
|
|
34
|
+
import { z } from "zod";
|
|
35
|
+
|
|
36
|
+
export const validatedTask = schemaTask({
|
|
37
|
+
id: "validated-task",
|
|
38
|
+
schema: z.object({
|
|
39
|
+
name: z.string(),
|
|
40
|
+
age: z.number(),
|
|
41
|
+
email: z.string().email(),
|
|
42
|
+
}),
|
|
43
|
+
run: async (payload) => {
|
|
44
|
+
// Payload is automatically validated and typed
|
|
45
|
+
return { message: `Hello ${payload.name}, age ${payload.age}` };
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Scheduled Task
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { schedules } from "@trigger.dev/sdk";
|
|
54
|
+
|
|
55
|
+
const dailyReport = schedules.task({
|
|
56
|
+
id: "daily-report",
|
|
57
|
+
cron: "0 9 * * *", // Daily at 9:00 AM UTC
|
|
58
|
+
// or with timezone: cron: { pattern: "0 9 * * *", timezone: "America/New_York" },
|
|
59
|
+
run: async (payload) => {
|
|
60
|
+
console.log("Scheduled run at:", payload.timestamp);
|
|
61
|
+
console.log("Last run was:", payload.lastTimestamp);
|
|
62
|
+
console.log("Next 5 runs:", payload.upcoming);
|
|
63
|
+
|
|
64
|
+
// Generate daily report logic
|
|
65
|
+
return { reportGenerated: true, date: payload.timestamp };
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Triggering Tasks
|
|
71
|
+
|
|
72
|
+
### From Backend Code
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { tasks } from "@trigger.dev/sdk";
|
|
76
|
+
import type { processData } from "./trigger/tasks";
|
|
77
|
+
|
|
78
|
+
// Single trigger
|
|
79
|
+
const handle = await tasks.trigger<typeof processData>("process-data", {
|
|
80
|
+
userId: "123",
|
|
81
|
+
data: [{ id: 1 }, { id: 2 }],
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Batch trigger
|
|
85
|
+
const batchHandle = await tasks.batchTrigger<typeof processData>("process-data", [
|
|
86
|
+
{ payload: { userId: "123", data: [{ id: 1 }] } },
|
|
87
|
+
{ payload: { userId: "456", data: [{ id: 2 }] } },
|
|
88
|
+
]);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### From Inside Tasks (with Result handling)
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
export const parentTask = task({
|
|
95
|
+
id: "parent-task",
|
|
96
|
+
run: async (payload) => {
|
|
97
|
+
// Trigger and continue
|
|
98
|
+
const handle = await childTask.trigger({ data: "value" });
|
|
99
|
+
|
|
100
|
+
// Trigger and wait - returns Result object, NOT task output
|
|
101
|
+
const result = await childTask.triggerAndWait({ data: "value" });
|
|
102
|
+
if (result.ok) {
|
|
103
|
+
console.log("Task output:", result.output); // Actual task return value
|
|
104
|
+
} else {
|
|
105
|
+
console.error("Task failed:", result.error);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Quick unwrap (throws on error)
|
|
109
|
+
const output = await childTask.triggerAndWait({ data: "value" }).unwrap();
|
|
110
|
+
|
|
111
|
+
// Batch trigger and wait
|
|
112
|
+
const results = await childTask.batchTriggerAndWait([
|
|
113
|
+
{ payload: { data: "item1" } },
|
|
114
|
+
{ payload: { data: "item2" } },
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
for (const run of results) {
|
|
118
|
+
if (run.ok) {
|
|
119
|
+
console.log("Success:", run.output);
|
|
120
|
+
} else {
|
|
121
|
+
console.log("Failed:", run.error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
export const childTask = task({
|
|
128
|
+
id: "child-task",
|
|
129
|
+
run: async (payload: { data: string }) => {
|
|
130
|
+
return { processed: payload.data };
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
> Never wrap triggerAndWait or batchTriggerAndWait calls in a Promise.all or Promise.allSettled as this is not supported in Trigger.dev tasks.
|
|
136
|
+
|
|
137
|
+
## Waits
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import { task, wait } from "@trigger.dev/sdk";
|
|
141
|
+
|
|
142
|
+
export const taskWithWaits = task({
|
|
143
|
+
id: "task-with-waits",
|
|
144
|
+
run: async (payload) => {
|
|
145
|
+
console.log("Starting task");
|
|
146
|
+
|
|
147
|
+
// Wait for specific duration
|
|
148
|
+
await wait.for({ seconds: 30 });
|
|
149
|
+
await wait.for({ minutes: 5 });
|
|
150
|
+
await wait.for({ hours: 1 });
|
|
151
|
+
await wait.for({ days: 1 });
|
|
152
|
+
|
|
153
|
+
// Wait until specific date
|
|
154
|
+
await wait.until({ date: new Date("2024-12-25") });
|
|
155
|
+
|
|
156
|
+
// Wait for token (from external system)
|
|
157
|
+
await wait.forToken({
|
|
158
|
+
token: "user-approval-token",
|
|
159
|
+
timeoutInSeconds: 3600, // 1 hour timeout
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
console.log("All waits completed");
|
|
163
|
+
return { status: "completed" };
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
> Never wrap wait calls in a Promise.all or Promise.allSettled as this is not supported in Trigger.dev tasks.
|
|
169
|
+
|
|
170
|
+
## Key Points
|
|
171
|
+
|
|
172
|
+
- **Result vs Output**: `triggerAndWait()` returns a `Result` object with `ok`, `output`, `error` properties - NOT the direct task output
|
|
173
|
+
- **Type safety**: Use `import type` for task references when triggering from backend
|
|
174
|
+
- **Waits > 5 seconds**: Automatically checkpointed, don't count toward compute usage
|
|
175
|
+
|
|
176
|
+
## NEVER Use (v2 deprecated)
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
// BREAKS APPLICATION
|
|
180
|
+
client.defineJob({
|
|
181
|
+
id: "job-id",
|
|
182
|
+
run: async (payload, io) => {
|
|
183
|
+
/* ... */
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Use v4 SDK (`@trigger.dev/sdk`), check `result.ok` before accessing `result.output`
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
<!-- TRIGGER.DEV basic START -->
|
|
2
|
+
# Trigger.dev Basic Tasks (v4)
|
|
3
|
+
|
|
4
|
+
**MUST use `@trigger.dev/sdk` (v4), NEVER `client.defineJob`**
|
|
5
|
+
|
|
6
|
+
## Basic Task
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { task } from "@trigger.dev/sdk";
|
|
10
|
+
|
|
11
|
+
export const processData = task({
|
|
12
|
+
id: "process-data",
|
|
13
|
+
retry: {
|
|
14
|
+
maxAttempts: 10,
|
|
15
|
+
factor: 1.8,
|
|
16
|
+
minTimeoutInMs: 500,
|
|
17
|
+
maxTimeoutInMs: 30_000,
|
|
18
|
+
randomize: false,
|
|
19
|
+
},
|
|
20
|
+
run: async (payload: { userId: string; data: any[] }) => {
|
|
21
|
+
// Task logic - runs for long time, no timeouts
|
|
22
|
+
console.log(`Processing ${payload.data.length} items for user ${payload.userId}`);
|
|
23
|
+
return { processed: payload.data.length };
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Schema Task (with validation)
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { schemaTask } from "@trigger.dev/sdk";
|
|
32
|
+
import { z } from "zod";
|
|
33
|
+
|
|
34
|
+
export const validatedTask = schemaTask({
|
|
35
|
+
id: "validated-task",
|
|
36
|
+
schema: z.object({
|
|
37
|
+
name: z.string(),
|
|
38
|
+
age: z.number(),
|
|
39
|
+
email: z.string().email(),
|
|
40
|
+
}),
|
|
41
|
+
run: async (payload) => {
|
|
42
|
+
// Payload is automatically validated and typed
|
|
43
|
+
return { message: `Hello ${payload.name}, age ${payload.age}` };
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Scheduled Task
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { schedules } from "@trigger.dev/sdk";
|
|
52
|
+
|
|
53
|
+
const dailyReport = schedules.task({
|
|
54
|
+
id: "daily-report",
|
|
55
|
+
cron: "0 9 * * *", // Daily at 9:00 AM UTC
|
|
56
|
+
// or with timezone: cron: { pattern: "0 9 * * *", timezone: "America/New_York" },
|
|
57
|
+
run: async (payload) => {
|
|
58
|
+
console.log("Scheduled run at:", payload.timestamp);
|
|
59
|
+
console.log("Last run was:", payload.lastTimestamp);
|
|
60
|
+
console.log("Next 5 runs:", payload.upcoming);
|
|
61
|
+
|
|
62
|
+
// Generate daily report logic
|
|
63
|
+
return { reportGenerated: true, date: payload.timestamp };
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Triggering Tasks
|
|
69
|
+
|
|
70
|
+
### From Backend Code
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { tasks } from "@trigger.dev/sdk";
|
|
74
|
+
import type { processData } from "./trigger/tasks";
|
|
75
|
+
|
|
76
|
+
// Single trigger
|
|
77
|
+
const handle = await tasks.trigger<typeof processData>("process-data", {
|
|
78
|
+
userId: "123",
|
|
79
|
+
data: [{ id: 1 }, { id: 2 }],
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Batch trigger
|
|
83
|
+
const batchHandle = await tasks.batchTrigger<typeof processData>("process-data", [
|
|
84
|
+
{ payload: { userId: "123", data: [{ id: 1 }] } },
|
|
85
|
+
{ payload: { userId: "456", data: [{ id: 2 }] } },
|
|
86
|
+
]);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### From Inside Tasks (with Result handling)
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
export const parentTask = task({
|
|
93
|
+
id: "parent-task",
|
|
94
|
+
run: async (payload) => {
|
|
95
|
+
// Trigger and continue
|
|
96
|
+
const handle = await childTask.trigger({ data: "value" });
|
|
97
|
+
|
|
98
|
+
// Trigger and wait - returns Result object, NOT task output
|
|
99
|
+
const result = await childTask.triggerAndWait({ data: "value" });
|
|
100
|
+
if (result.ok) {
|
|
101
|
+
console.log("Task output:", result.output); // Actual task return value
|
|
102
|
+
} else {
|
|
103
|
+
console.error("Task failed:", result.error);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Quick unwrap (throws on error)
|
|
107
|
+
const output = await childTask.triggerAndWait({ data: "value" }).unwrap();
|
|
108
|
+
|
|
109
|
+
// Batch trigger and wait
|
|
110
|
+
const results = await childTask.batchTriggerAndWait([
|
|
111
|
+
{ payload: { data: "item1" } },
|
|
112
|
+
{ payload: { data: "item2" } },
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
for (const run of results) {
|
|
116
|
+
if (run.ok) {
|
|
117
|
+
console.log("Success:", run.output);
|
|
118
|
+
} else {
|
|
119
|
+
console.log("Failed:", run.error);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
export const childTask = task({
|
|
126
|
+
id: "child-task",
|
|
127
|
+
run: async (payload: { data: string }) => {
|
|
128
|
+
return { processed: payload.data };
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
> Never wrap triggerAndWait or batchTriggerAndWait calls in a Promise.all or Promise.allSettled as this is not supported in Trigger.dev tasks.
|
|
134
|
+
|
|
135
|
+
## Waits
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { task, wait } from "@trigger.dev/sdk";
|
|
139
|
+
|
|
140
|
+
export const taskWithWaits = task({
|
|
141
|
+
id: "task-with-waits",
|
|
142
|
+
run: async (payload) => {
|
|
143
|
+
console.log("Starting task");
|
|
144
|
+
|
|
145
|
+
// Wait for specific duration
|
|
146
|
+
await wait.for({ seconds: 30 });
|
|
147
|
+
await wait.for({ minutes: 5 });
|
|
148
|
+
await wait.for({ hours: 1 });
|
|
149
|
+
await wait.for({ days: 1 });
|
|
150
|
+
|
|
151
|
+
// Wait until specific date
|
|
152
|
+
await wait.until({ date: new Date("2024-12-25") });
|
|
153
|
+
|
|
154
|
+
// Wait for token (from external system)
|
|
155
|
+
await wait.forToken({
|
|
156
|
+
token: "user-approval-token",
|
|
157
|
+
timeoutInSeconds: 3600, // 1 hour timeout
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
console.log("All waits completed");
|
|
161
|
+
return { status: "completed" };
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
> Never wrap wait calls in a Promise.all or Promise.allSettled as this is not supported in Trigger.dev tasks.
|
|
167
|
+
|
|
168
|
+
## Key Points
|
|
169
|
+
|
|
170
|
+
- **Result vs Output**: `triggerAndWait()` returns a `Result` object with `ok`, `output`, `error` properties - NOT the direct task output
|
|
171
|
+
- **Type safety**: Use `import type` for task references when triggering from backend
|
|
172
|
+
- **Waits > 5 seconds**: Automatically checkpointed, don't count toward compute usage
|
|
173
|
+
|
|
174
|
+
## NEVER Use (v2 deprecated)
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
// BREAKS APPLICATION
|
|
178
|
+
client.defineJob({
|
|
179
|
+
id: "job-id",
|
|
180
|
+
run: async (payload, io) => {
|
|
181
|
+
/* ... */
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Use v4 SDK (`@trigger.dev/sdk`), check `result.ok` before accessing `result.output`
|
|
187
|
+
|
|
188
|
+
<!-- TRIGGER.DEV basic END -->
|