-
Notifications
You must be signed in to change notification settings - Fork 78
feat: preview workflows #866
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
Open
felipefreitag
wants to merge
23
commits into
canary
Choose a base branch
from
preview-workflows
base: canary
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
a5838a8
feat: workflows
felipefreitag d774651
chore: bump version
felipefreitag 63f557f
feat: add events and patch workflow
felipefreitag 02d2781
fix: update workflow create response
felipefreitag 92f7bf6
fix: update event schema validation
felipefreitag 03165b8
fix: linter
felipefreitag 0ff3c50
fix: update types
felipefreitag 5aef44a
feat: add workflow runs list and details
felipefreitag fcd1f7e
feat: add workflow run steps
felipefreitag 1d6e316
fix: remove implementation details
felipefreitag 46f35a6
feat: add steps payload
felipefreitag 216d665
feat: improve workflow types
felipefreitag c09435e
chore: bump package
felipefreitag e9640e4
fix:lint
felipefreitag 5007659
fix: types
felipefreitag 557f8bd
fix: remove type repetition
felipefreitag fe596d9
fix: lint
felipefreitag 33a856a
move to automations
vcapretz 1b5b2d6
use automations endpoint
vcapretz 84f40da
chore: bump package version
CarolinaMoraes 7e25f6d
feat: remove workflows namespace from SDK (#898)
vcapretz 646480b
fix send event
vcapretz 3e2d00f
new version
vcapretz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,207 @@ | ||
| import createFetchMock from 'vitest-fetch-mock'; | ||
| import { Resend } from '../resend'; | ||
| import { | ||
| mockErrorResponse, | ||
| mockSuccessResponse, | ||
| } from '../test-utils/mock-fetch'; | ||
| import type { | ||
| GetAutomationRunStepOptions, | ||
| GetAutomationRunStepResponseSuccess, | ||
| } from './interfaces/get-automation-run-step.interface'; | ||
| import type { | ||
| ListAutomationRunStepsOptions, | ||
| ListAutomationRunStepsResponseSuccess, | ||
| } from './interfaces/list-automation-run-steps.interface'; | ||
|
|
||
| const fetchMocker = createFetchMock(vi); | ||
| fetchMocker.enableMocks(); | ||
|
|
||
| afterEach(() => fetchMock.resetMocks()); | ||
| afterAll(() => fetchMocker.disableMocks()); | ||
|
|
||
| describe('get', () => { | ||
| it('gets a automation run step', async () => { | ||
| const options: GetAutomationRunStepOptions = { | ||
| automationId: 'wf_123', | ||
| runId: 'wr_456', | ||
| stepId: 'wrs_789', | ||
| }; | ||
| const response: GetAutomationRunStepResponseSuccess = { | ||
| object: 'automation_run_step', | ||
| id: 'wrs_789', | ||
| step_id: 'step_1', | ||
| type: 'trigger', | ||
| config: { event_name: 'user.created' }, | ||
| status: 'completed', | ||
| started_at: '2024-01-01T00:00:00.000Z', | ||
| completed_at: '2024-01-01T00:01:00.000Z', | ||
| created_at: '2024-01-01T00:00:00.000Z', | ||
| }; | ||
|
|
||
| mockSuccessResponse(response, {}); | ||
|
|
||
| const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop'); | ||
| await expect( | ||
| resend.automations.runs.steps.get(options), | ||
| ).resolves.toMatchInlineSnapshot(` | ||
| { | ||
| "data": { | ||
| "completed_at": "2024-01-01T00:01:00.000Z", | ||
| "config": { | ||
| "event_name": "user.created", | ||
| }, | ||
| "created_at": "2024-01-01T00:00:00.000Z", | ||
| "id": "wrs_789", | ||
| "object": "automation_run_step", | ||
| "started_at": "2024-01-01T00:00:00.000Z", | ||
| "status": "completed", | ||
| "step_id": "step_1", | ||
| "type": "trigger", | ||
| }, | ||
| "error": null, | ||
| "headers": { | ||
| "content-type": "application/json", | ||
| }, | ||
| } | ||
| `); | ||
| }); | ||
|
|
||
| it('returns error', async () => { | ||
| const options: GetAutomationRunStepOptions = { | ||
| automationId: 'wf_123', | ||
| runId: 'wr_456', | ||
| stepId: 'wrs_invalid', | ||
| }; | ||
|
|
||
| mockErrorResponse( | ||
| { name: 'not_found', message: 'Automation run step not found' }, | ||
| {}, | ||
| ); | ||
|
|
||
| const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop'); | ||
| const result = await resend.automations.runs.steps.get(options); | ||
| expect(result.error).not.toBeNull(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('list', () => { | ||
| it('lists automation run steps', async () => { | ||
| const options: ListAutomationRunStepsOptions = { | ||
| automationId: 'wf_123', | ||
| runId: 'wr_456', | ||
| }; | ||
| const response: ListAutomationRunStepsResponseSuccess = { | ||
| object: 'list', | ||
| data: [ | ||
| { | ||
| id: 'wrs_789', | ||
| step_id: 'step_1', | ||
| type: 'trigger', | ||
| status: 'completed', | ||
| started_at: '2024-01-01T00:00:00.000Z', | ||
| completed_at: '2024-01-01T00:01:00.000Z', | ||
| created_at: '2024-01-01T00:00:00.000Z', | ||
| }, | ||
| ], | ||
| has_more: false, | ||
| }; | ||
|
|
||
| mockSuccessResponse(response, {}); | ||
|
|
||
| const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop'); | ||
| await expect( | ||
| resend.automations.runs.steps.list(options), | ||
| ).resolves.toMatchInlineSnapshot(` | ||
| { | ||
| "data": { | ||
| "data": [ | ||
| { | ||
| "completed_at": "2024-01-01T00:01:00.000Z", | ||
| "created_at": "2024-01-01T00:00:00.000Z", | ||
| "id": "wrs_789", | ||
| "started_at": "2024-01-01T00:00:00.000Z", | ||
| "status": "completed", | ||
| "step_id": "step_1", | ||
| "type": "trigger", | ||
| }, | ||
| ], | ||
| "has_more": false, | ||
| "object": "list", | ||
| }, | ||
| "error": null, | ||
| "headers": { | ||
| "content-type": "application/json", | ||
| }, | ||
| } | ||
| `); | ||
| }); | ||
|
|
||
| it('lists automation run steps with pagination', async () => { | ||
| const options: ListAutomationRunStepsOptions = { | ||
| automationId: 'wf_123', | ||
| runId: 'wr_456', | ||
| limit: 1, | ||
| after: 'wrs_cursor', | ||
| }; | ||
| const response: ListAutomationRunStepsResponseSuccess = { | ||
| object: 'list', | ||
| data: [ | ||
| { | ||
| id: 'wrs_101', | ||
| step_id: 'step_2', | ||
| type: 'send_email', | ||
| status: 'running', | ||
| started_at: '2024-01-02T00:00:00.000Z', | ||
| completed_at: null, | ||
| created_at: '2024-01-02T00:00:00.000Z', | ||
| }, | ||
| ], | ||
| has_more: true, | ||
| }; | ||
|
|
||
| mockSuccessResponse(response, {}); | ||
|
|
||
| const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop'); | ||
| await expect( | ||
| resend.automations.runs.steps.list(options), | ||
| ).resolves.toMatchInlineSnapshot(` | ||
| { | ||
| "data": { | ||
| "data": [ | ||
| { | ||
| "completed_at": null, | ||
| "created_at": "2024-01-02T00:00:00.000Z", | ||
| "id": "wrs_101", | ||
| "started_at": "2024-01-02T00:00:00.000Z", | ||
| "status": "running", | ||
| "step_id": "step_2", | ||
| "type": "send_email", | ||
| }, | ||
| ], | ||
| "has_more": true, | ||
| "object": "list", | ||
| }, | ||
| "error": null, | ||
| "headers": { | ||
| "content-type": "application/json", | ||
| }, | ||
| } | ||
| `); | ||
| }); | ||
|
|
||
| it('returns error', async () => { | ||
| const options: ListAutomationRunStepsOptions = { | ||
| automationId: 'wf_invalid', | ||
| runId: 'wr_invalid', | ||
| }; | ||
|
|
||
| mockErrorResponse( | ||
| { name: 'not_found', message: 'Automation not found' }, | ||
| {}, | ||
| ); | ||
|
|
||
| const resend = new Resend('re_zKa4RCko_Lhm9ost2YjNCctnPjbLw8Nop'); | ||
| const result = await resend.automations.runs.steps.list(options); | ||
| expect(result.error).not.toBeNull(); | ||
| }); | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import { buildPaginationQuery } from '../common/utils/build-pagination-query'; | ||
| import type { Resend } from '../resend'; | ||
| import type { | ||
| GetAutomationRunStepOptions, | ||
| GetAutomationRunStepResponse, | ||
| GetAutomationRunStepResponseSuccess, | ||
| } from './interfaces/get-automation-run-step.interface'; | ||
| import type { | ||
| ListAutomationRunStepsOptions, | ||
| ListAutomationRunStepsResponse, | ||
| ListAutomationRunStepsResponseSuccess, | ||
| } from './interfaces/list-automation-run-steps.interface'; | ||
|
|
||
| export class AutomationRunSteps { | ||
| constructor(private readonly resend: Resend) {} | ||
|
|
||
| async get( | ||
| options: GetAutomationRunStepOptions, | ||
| ): Promise<GetAutomationRunStepResponse> { | ||
| const data = await this.resend.get<GetAutomationRunStepResponseSuccess>( | ||
| `/automations/${options.automationId}/runs/${options.runId}/steps/${options.stepId}`, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Custom agent: API Key Permission Check SDK Methods Confirm production API keys have permission to access the new automation run steps endpoints (get/list). The rule requires this check for newly introduced SDK methods to avoid permission failures after deployment. Prompt for AI agents |
||
| ); | ||
| return data; | ||
| } | ||
|
|
||
| async list( | ||
| options: ListAutomationRunStepsOptions, | ||
| ): Promise<ListAutomationRunStepsResponse> { | ||
| const queryString = buildPaginationQuery(options); | ||
| const url = queryString | ||
| ? `/automations/${options.automationId}/runs/${options.runId}/steps?${queryString}` | ||
| : `/automations/${options.automationId}/runs/${options.runId}/steps`; | ||
|
|
||
| const data = | ||
| await this.resend.get<ListAutomationRunStepsResponseSuccess>(url); | ||
| return data; | ||
| } | ||
| } | ||
32 changes: 32 additions & 0 deletions
32
src/automation-run-steps/interfaces/automation-run-step.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import type { AutomationStepType } from '../../automations/interfaces/automation-step.interface'; | ||
|
|
||
| export type AutomationRunStepStatus = | ||
| | 'pending' | ||
| | 'running' | ||
| | 'completed' | ||
| | 'failed' | ||
| | 'skipped' | ||
| | 'waiting'; | ||
|
|
||
| export interface AutomationRunStep { | ||
| object: 'automation_run_step'; | ||
| id: string; | ||
| step_id: string; | ||
| type: AutomationStepType; | ||
| config: Record<string, unknown>; | ||
| status: AutomationRunStepStatus; | ||
| started_at: string | null; | ||
| completed_at: string | null; | ||
| created_at: string; | ||
| } | ||
|
|
||
| export type AutomationRunStepItem = Pick< | ||
| AutomationRunStep, | ||
| | 'id' | ||
| | 'step_id' | ||
| | 'type' | ||
| | 'status' | ||
| | 'started_at' | ||
| | 'completed_at' | ||
| | 'created_at' | ||
| >; |
13 changes: 13 additions & 0 deletions
13
src/automation-run-steps/interfaces/get-automation-run-step.interface.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import type { Response } from '../../interfaces'; | ||
| import type { AutomationRunStep } from './automation-run-step'; | ||
|
|
||
| export interface GetAutomationRunStepOptions { | ||
| automationId: string; | ||
| runId: string; | ||
| stepId: string; | ||
| } | ||
|
|
||
| export type GetAutomationRunStepResponseSuccess = AutomationRunStep; | ||
|
|
||
| export type GetAutomationRunStepResponse = | ||
| Response<GetAutomationRunStepResponseSuccess>; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| export * from './automation-run-step'; | ||
| export * from './get-automation-run-step.interface'; | ||
| export * from './list-automation-run-steps.interface'; |
18 changes: 18 additions & 0 deletions
18
src/automation-run-steps/interfaces/list-automation-run-steps.interface.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import type { | ||
| PaginatedData, | ||
| PaginationOptions, | ||
| } from '../../common/interfaces/pagination-options.interface'; | ||
| import type { Response } from '../../interfaces'; | ||
| import type { AutomationRunStepItem } from './automation-run-step'; | ||
|
|
||
| export type ListAutomationRunStepsOptions = PaginationOptions & { | ||
| automationId: string; | ||
| runId: string; | ||
| }; | ||
|
|
||
| export type ListAutomationRunStepsResponseSuccess = PaginatedData< | ||
| AutomationRunStepItem[] | ||
| >; | ||
|
|
||
| export type ListAutomationRunStepsResponse = | ||
| Response<ListAutomationRunStepsResponseSuccess>; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Redact the API key literal in tests; use a non-secret dummy value instead.
(Based on your team's feedback about redacting secrets.)
View Feedback
Prompt for AI agents