Skip to content

Commit 59a94c7

Browse files
authored
Fixes #583 by filtering out properties with missing values (#584)
This also improves the retrying behavior of the resend integration by skipping retrying certain client errors
1 parent 4cd97c8 commit 59a94c7

6 files changed

Lines changed: 57 additions & 2 deletions

File tree

.changeset/sharp-lobsters-cross.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@trigger.dev/resend": patch
3+
"@trigger.dev/core": patch
4+
---
5+
6+
Allow task property values to be blank, but strip them out before persisting them

apps/webapp/app/routes/api.v1.runs.$runId.tasks.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ export class RunTaskService {
280280
noop: taskBody.noop,
281281
delayUntil: taskBody.delayUntil,
282282
params: taskBody.params ?? undefined,
283-
properties: taskBody.properties ?? undefined,
283+
properties: this.#filterProperties(taskBody.properties) ?? undefined,
284284
redact: taskBody.redact ?? undefined,
285285
operation: taskBody.operation,
286286
callbackUrl,
@@ -325,4 +325,14 @@ export class RunTaskService {
325325

326326
return task ? taskWithAttemptsToServerTask(task) : undefined;
327327
}
328+
329+
#filterProperties(properties: RunTaskBodyOutput["properties"]): RunTaskBodyOutput["properties"] {
330+
if (!properties) return;
331+
332+
return properties.filter((property) => {
333+
if (!property) return false;
334+
335+
return typeof property.label === "string" && typeof property.text === "string";
336+
});
337+
}
328338
}

docs/sdk/io/runtask.mdx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,15 @@ The wrappers at `io.integration.runTask()` expose the underlying Integration cli
128128
The value of the property.
129129
</ResponseField>
130130
</Expandable>
131+
131132
</ResponseField>
132133

133134
</Expandable>
134135
</ResponseField>
135136

136137
<ResponseField name="onError" type="function">
137138
An optional callback that will be called when the Task fails. You can perform
138-
logic in here and optionally return a custom error object. Returning an object with `{ retryAt: Date, error?: Error }` will retry the Task at the specified Date. You can also just return a new `Error` object to throw a new error. Return nothing to rethrow the original error.
139+
logic in here and optionally return a custom error object. Returning an object with `{ retryAt: Date, error?: Error }` will retry the Task at the specified Date. You can also just return a new `Error` object to throw a new error. Returning `null` or `undefined` will rethrow the original error. If you want to force retrying to be skipped, return `{ skipRetrying: true }`.
139140

140141
<Expandable title="arguments">
141142
<ResponseField name="error" type="unknown">

integrations/resend/src/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ function isRequestError(error: unknown): error is ErrorResponse {
2525
return typeof error === "object" && error !== null && "statusCode" in error;
2626
}
2727

28+
// See https://resend.com/docs/api-reference/errors
29+
const skipRetryingErrors = [422, 401, 403, 404, 405, 422];
30+
2831
function onError(error: unknown) {
2932
if (!isRequestError(error)) {
3033
if (error instanceof Error) {
@@ -34,6 +37,12 @@ function onError(error: unknown) {
3437
return new Error("Unknown error");
3538
}
3639

40+
if (skipRetryingErrors.includes(error.statusCode)) {
41+
return {
42+
skipRetrying: true,
43+
};
44+
}
45+
3746
return new Error(error.message);
3847
}
3948

packages/core/src/schemas/api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ export const RunTaskBodyInputSchema = RunTaskOptionsSchema.extend({
664664
export type RunTaskBodyInput = z.infer<typeof RunTaskBodyInputSchema>;
665665

666666
export const RunTaskBodyOutputSchema = RunTaskBodyInputSchema.extend({
667+
properties: z.array(DisplayPropertySchema.partial()).optional(),
667668
params: DeserializedJsonSchema.optional().nullable(),
668669
callback: z
669670
.object({

references/job-catalog/src/resend.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,32 @@ client.defineJob({
4343
},
4444
});
4545

46+
client.defineJob({
47+
id: "send-resend-email-from-blank",
48+
name: "Send Resend Email From Blank",
49+
version: "0.1.0",
50+
trigger: eventTrigger({
51+
name: "send.email",
52+
schema: z.object({
53+
to: z.union([z.string(), z.array(z.string())]),
54+
subject: z.string(),
55+
text: z.string(),
56+
from: z.string().optional(),
57+
}),
58+
}),
59+
integrations: {
60+
resend,
61+
},
62+
run: async (payload, io, ctx) => {
63+
const response = await io.resend.sendEmail("📧", {
64+
to: payload.to,
65+
subject: payload.subject,
66+
text: payload.text,
67+
from: payload.from!,
68+
});
69+
70+
await io.logger.info("Sent email", { response });
71+
},
72+
});
73+
4674
createExpressServer(client);

0 commit comments

Comments
 (0)