Skip to content

Commit 9fe080c

Browse files
cursoragentvcapretz
andcommitted
merge: bring in preview-workflows branch (resolve conflict keeping canary version)
Co-authored-by: Vitor Capretz <capretzvitor@gmail.com>
2 parents ed788b1 + 84f40da commit 9fe080c

File tree

58 files changed

+3489
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+3489
-0
lines changed
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
import createFetchMock from 'vitest-fetch-mock';
2+
import { Resend } from '../resend';
3+
import {
4+
mockErrorResponse,
5+
mockSuccessResponse,
6+
} from '../test-utils/mock-fetch';
7+
import type {
8+
GetAutomationRunStepOptions,
9+
GetAutomationRunStepResponseSuccess,
10+
} from './interfaces/get-automation-run-step.interface';
11+
import type {
12+
ListAutomationRunStepsOptions,
13+
ListAutomationRunStepsResponseSuccess,
14+
} from './interfaces/list-automation-run-steps.interface';
15+
16+
const fetchMocker = createFetchMock(vi);
17+
fetchMocker.enableMocks();
18+
19+
afterEach(() => fetchMock.resetMocks());
20+
afterAll(() => fetchMocker.disableMocks());
21+
22+
describe('get', () => {
23+
it('gets a automation run step', async () => {
24+
const options: GetAutomationRunStepOptions = {
25+
automationId: 'wf_123',
26+
runId: 'wr_456',
27+
stepId: 'wrs_789',
28+
};
29+
const response: GetAutomationRunStepResponseSuccess = {
30+
object: 'automation_run_step',
31+
id: 'wrs_789',
32+
step_id: 'step_1',
33+
type: 'trigger',
34+
config: { event_name: 'user.created' },
35+
status: 'completed',
36+
started_at: '2024-01-01T00:00:00.000Z',
37+
completed_at: '2024-01-01T00:01:00.000Z',
38+
created_at: '2024-01-01T00:00:00.000Z',
39+
};
40+
41+
mockSuccessResponse(response, {});
42+
43+
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
44+
await expect(
45+
resend.automations.runs.steps.get(options),
46+
).resolves.toMatchInlineSnapshot(`
47+
{
48+
"data": {
49+
"completed_at": "2024-01-01T00:01:00.000Z",
50+
"config": {
51+
"event_name": "user.created",
52+
},
53+
"created_at": "2024-01-01T00:00:00.000Z",
54+
"id": "wrs_789",
55+
"object": "automation_run_step",
56+
"started_at": "2024-01-01T00:00:00.000Z",
57+
"status": "completed",
58+
"step_id": "step_1",
59+
"type": "trigger",
60+
},
61+
"error": null,
62+
"headers": {
63+
"content-type": "application/json",
64+
},
65+
}
66+
`);
67+
});
68+
69+
it('returns error', async () => {
70+
const options: GetAutomationRunStepOptions = {
71+
automationId: 'wf_123',
72+
runId: 'wr_456',
73+
stepId: 'wrs_invalid',
74+
};
75+
76+
mockErrorResponse(
77+
{ name: 'not_found', message: 'Automation run step not found' },
78+
{},
79+
);
80+
81+
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
82+
const result = await resend.automations.runs.steps.get(options);
83+
expect(result.error).not.toBeNull();
84+
});
85+
});
86+
87+
describe('list', () => {
88+
it('lists automation run steps', async () => {
89+
const options: ListAutomationRunStepsOptions = {
90+
automationId: 'wf_123',
91+
runId: 'wr_456',
92+
};
93+
const response: ListAutomationRunStepsResponseSuccess = {
94+
object: 'list',
95+
data: [
96+
{
97+
id: 'wrs_789',
98+
step_id: 'step_1',
99+
type: 'trigger',
100+
status: 'completed',
101+
started_at: '2024-01-01T00:00:00.000Z',
102+
completed_at: '2024-01-01T00:01:00.000Z',
103+
created_at: '2024-01-01T00:00:00.000Z',
104+
},
105+
],
106+
has_more: false,
107+
};
108+
109+
mockSuccessResponse(response, {});
110+
111+
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
112+
await expect(
113+
resend.automations.runs.steps.list(options),
114+
).resolves.toMatchInlineSnapshot(`
115+
{
116+
"data": {
117+
"data": [
118+
{
119+
"completed_at": "2024-01-01T00:01:00.000Z",
120+
"created_at": "2024-01-01T00:00:00.000Z",
121+
"id": "wrs_789",
122+
"started_at": "2024-01-01T00:00:00.000Z",
123+
"status": "completed",
124+
"step_id": "step_1",
125+
"type": "trigger",
126+
},
127+
],
128+
"has_more": false,
129+
"object": "list",
130+
},
131+
"error": null,
132+
"headers": {
133+
"content-type": "application/json",
134+
},
135+
}
136+
`);
137+
});
138+
139+
it('lists automation run steps with pagination', async () => {
140+
const options: ListAutomationRunStepsOptions = {
141+
automationId: 'wf_123',
142+
runId: 'wr_456',
143+
limit: 1,
144+
after: 'wrs_cursor',
145+
};
146+
const response: ListAutomationRunStepsResponseSuccess = {
147+
object: 'list',
148+
data: [
149+
{
150+
id: 'wrs_101',
151+
step_id: 'step_2',
152+
type: 'send_email',
153+
status: 'running',
154+
started_at: '2024-01-02T00:00:00.000Z',
155+
completed_at: null,
156+
created_at: '2024-01-02T00:00:00.000Z',
157+
},
158+
],
159+
has_more: true,
160+
};
161+
162+
mockSuccessResponse(response, {});
163+
164+
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
165+
await expect(
166+
resend.automations.runs.steps.list(options),
167+
).resolves.toMatchInlineSnapshot(`
168+
{
169+
"data": {
170+
"data": [
171+
{
172+
"completed_at": null,
173+
"created_at": "2024-01-02T00:00:00.000Z",
174+
"id": "wrs_101",
175+
"started_at": "2024-01-02T00:00:00.000Z",
176+
"status": "running",
177+
"step_id": "step_2",
178+
"type": "send_email",
179+
},
180+
],
181+
"has_more": true,
182+
"object": "list",
183+
},
184+
"error": null,
185+
"headers": {
186+
"content-type": "application/json",
187+
},
188+
}
189+
`);
190+
});
191+
192+
it('returns error', async () => {
193+
const options: ListAutomationRunStepsOptions = {
194+
automationId: 'wf_invalid',
195+
runId: 'wr_invalid',
196+
};
197+
198+
mockErrorResponse(
199+
{ name: 'not_found', message: 'Automation not found' },
200+
{},
201+
);
202+
203+
const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop');
204+
const result = await resend.automations.runs.steps.list(options);
205+
expect(result.error).not.toBeNull();
206+
});
207+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { buildPaginationQuery } from '../common/utils/build-pagination-query';
2+
import type { Resend } from '../resend';
3+
import type {
4+
GetAutomationRunStepOptions,
5+
GetAutomationRunStepResponse,
6+
GetAutomationRunStepResponseSuccess,
7+
} from './interfaces/get-automation-run-step.interface';
8+
import type {
9+
ListAutomationRunStepsOptions,
10+
ListAutomationRunStepsResponse,
11+
ListAutomationRunStepsResponseSuccess,
12+
} from './interfaces/list-automation-run-steps.interface';
13+
14+
export class AutomationRunSteps {
15+
constructor(private readonly resend: Resend) {}
16+
17+
async get(
18+
options: GetAutomationRunStepOptions,
19+
): Promise<GetAutomationRunStepResponse> {
20+
const data = await this.resend.get<GetAutomationRunStepResponseSuccess>(
21+
`/automations/${options.automationId}/runs/${options.runId}/steps/${options.stepId}`,
22+
);
23+
return data;
24+
}
25+
26+
async list(
27+
options: ListAutomationRunStepsOptions,
28+
): Promise<ListAutomationRunStepsResponse> {
29+
const queryString = buildPaginationQuery(options);
30+
const url = queryString
31+
? `/automations/${options.automationId}/runs/${options.runId}/steps?${queryString}`
32+
: `/automations/${options.automationId}/runs/${options.runId}/steps`;
33+
34+
const data =
35+
await this.resend.get<ListAutomationRunStepsResponseSuccess>(url);
36+
return data;
37+
}
38+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import type { AutomationStepType } from '../../automations/interfaces/automation-step.interface';
2+
3+
export type AutomationRunStepStatus =
4+
| 'pending'
5+
| 'running'
6+
| 'completed'
7+
| 'failed'
8+
| 'skipped'
9+
| 'waiting';
10+
11+
export interface AutomationRunStep {
12+
object: 'automation_run_step';
13+
id: string;
14+
step_id: string;
15+
type: AutomationStepType;
16+
config: Record<string, unknown>;
17+
status: AutomationRunStepStatus;
18+
started_at: string | null;
19+
completed_at: string | null;
20+
created_at: string;
21+
}
22+
23+
export type AutomationRunStepItem = Pick<
24+
AutomationRunStep,
25+
| 'id'
26+
| 'step_id'
27+
| 'type'
28+
| 'status'
29+
| 'started_at'
30+
| 'completed_at'
31+
| 'created_at'
32+
>;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { Response } from '../../interfaces';
2+
import type { AutomationRunStep } from './automation-run-step';
3+
4+
export interface GetAutomationRunStepOptions {
5+
automationId: string;
6+
runId: string;
7+
stepId: string;
8+
}
9+
10+
export type GetAutomationRunStepResponseSuccess = AutomationRunStep;
11+
12+
export type GetAutomationRunStepResponse =
13+
Response<GetAutomationRunStepResponseSuccess>;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './automation-run-step';
2+
export * from './get-automation-run-step.interface';
3+
export * from './list-automation-run-steps.interface';
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type {
2+
PaginatedData,
3+
PaginationOptions,
4+
} from '../../common/interfaces/pagination-options.interface';
5+
import type { Response } from '../../interfaces';
6+
import type { AutomationRunStepItem } from './automation-run-step';
7+
8+
export type ListAutomationRunStepsOptions = PaginationOptions & {
9+
automationId: string;
10+
runId: string;
11+
};
12+
13+
export type ListAutomationRunStepsResponseSuccess = PaginatedData<
14+
AutomationRunStepItem[]
15+
>;
16+
17+
export type ListAutomationRunStepsResponse =
18+
Response<ListAutomationRunStepsResponseSuccess>;

0 commit comments

Comments
 (0)