feat(gmail): added gmail polling service to trigger workflow on incoming emails (#344)

* setup gmail polling service, not tested

* general improvements to gmail polling and error handling, receive message but triggers wrong wrokflow

* finished gmail polling service, works when I send multiple emails in a single polling period (triggers the workflow for each new email)

* remove unread messages

* remove unread messages

* modified to process all incoming emails as individual workflow executions, enhance dedupe, general improvements

* replaced desc w tooltips

* added cron job for polling gmail

* remove unused props, simplify naming convention

* renoved extraneous comments, removed unused processIncomingEmails

* fixed build issues

* acknowledged PR comments
This commit is contained in:
Waleed Latif
2025-05-11 12:46:09 -07:00
committed by GitHub
parent d79cad4c52
commit 0fc0f683a6
38 changed files with 1682 additions and 156 deletions

View File

@@ -112,44 +112,47 @@ describe('Gmail Read Tool', () => {
// Then setup response for the first message
const originalFetch = global.fetch
global.fetch = vi.fn().mockImplementation((url, options) => {
// Check if it's a token request
if (url.toString().includes('/api/auth/oauth/token')) {
return Promise.resolve({
ok: true,
status: 200,
json: () => Promise.resolve({ accessToken: 'gmail-access-token-123' }),
})
}
global.fetch = Object.assign(
vi.fn().mockImplementation((url, options) => {
// Check if it's a token request
if (url.toString().includes('/api/auth/oauth/token')) {
return Promise.resolve({
ok: true,
status: 200,
json: () => Promise.resolve({ accessToken: 'gmail-access-token-123' }),
})
}
// For message list endpoint
if (url.toString().includes('users/me/messages') && !url.toString().includes('msg1')) {
return Promise.resolve({
ok: true,
status: 200,
json: () => Promise.resolve(mockGmailResponses.messageList),
headers: {
get: () => 'application/json',
forEach: () => {},
},
})
}
// For message list endpoint
if (url.toString().includes('users/me/messages') && !url.toString().includes('msg1')) {
return Promise.resolve({
ok: true,
status: 200,
json: () => Promise.resolve(mockGmailResponses.messageList),
headers: {
get: () => 'application/json',
forEach: () => {},
},
})
}
// For specific message endpoint
if (url.toString().includes('msg1')) {
return Promise.resolve({
ok: true,
status: 200,
json: () => Promise.resolve(mockGmailResponses.singleMessage),
headers: {
get: () => 'application/json',
forEach: () => {},
},
})
}
// For specific message endpoint
if (url.toString().includes('msg1')) {
return Promise.resolve({
ok: true,
status: 200,
json: () => Promise.resolve(mockGmailResponses.singleMessage),
headers: {
get: () => 'application/json',
forEach: () => {},
},
})
}
return originalFetch(url, options)
})
return originalFetch(url, options)
}),
{ preconnect: vi.fn() }
) as typeof fetch
// Execute with credential instead of access token
await tester.execute({
@@ -196,31 +199,34 @@ describe('Gmail Read Tool', () => {
const originalFetch = global.fetch
// First setup response for message list
global.fetch = vi
.fn()
.mockImplementationOnce((url, options) => {
return Promise.resolve({
ok: true,
status: 200,
json: () => Promise.resolve(mockGmailResponses.messageList),
headers: {
get: () => 'application/json',
forEach: () => {},
},
global.fetch = Object.assign(
vi
.fn()
.mockImplementationOnce((url, options) => {
return Promise.resolve({
ok: true,
status: 200,
json: () => Promise.resolve(mockGmailResponses.messageList),
headers: {
get: () => 'application/json',
forEach: () => {},
},
})
})
})
.mockImplementationOnce((url, options) => {
// For the second request (first message)
return Promise.resolve({
ok: true,
status: 200,
json: () => Promise.resolve(mockGmailResponses.singleMessage),
headers: {
get: () => 'application/json',
forEach: () => {},
},
})
})
.mockImplementationOnce((url, options) => {
// For the second request (first message)
return Promise.resolve({
ok: true,
status: 200,
json: () => Promise.resolve(mockGmailResponses.singleMessage),
headers: {
get: () => 'application/json',
forEach: () => {},
},
})
}),
{ preconnect: vi.fn() }
) as typeof fetch
// Execute the tool
const result = await tester.execute({