import { AuthenticationType, DedupeStrategy, httpClient, HttpMethod, Polling, pollingHelper, QueryParams, } from '@activepieces/pieces-common'; import { getHubspotAccessToken, hubspotAuth } from '../auth'; import { createTrigger, Property, TriggerStrategy, } from '@activepieces/pieces-framework'; import { AppConnectionValueForAuthProperty } from '@activepieces/pieces-framework'; type Props = { eventType?: string; }; type EmailEventResponse = { events: Array>; hasMore: boolean; offset: string; }; const polling: Polling, Props> = { strategy: DedupeStrategy.TIMEBASED, async items({ auth, propsValue, lastFetchEpochMS }) { const eventType = propsValue.eventType; const isTestMode = lastFetchEpochMS === 0; let hasMore = true; const qs: QueryParams = { limit: '100' }; if (eventType) { qs.eventType = eventType; } if (lastFetchEpochMS) { qs.startTimestamp = lastFetchEpochMS.toString(); } const emailEvents = []; do { const response = await httpClient.sendRequest({ method: HttpMethod.GET, url: 'https://api.hubapi.com/email/public/v1/events', queryParams: qs, authentication: { type: AuthenticationType.BEARER_TOKEN, token: getHubspotAccessToken(auth), }, }); hasMore = response.body.hasMore; qs.offset = response.body.offset; for (const event of response.body.events) { emailEvents.push(event); } if (isTestMode) break; } while (hasMore); return emailEvents.map((item) => ({ epochMilliSeconds: item['created'] as number, data: item, })); }, }; export const newEmailEventTrigger = createTrigger({ auth: hubspotAuth, name: 'new-email-event', classification: 'READ', displayName: 'New Email Event', description: 'Triggers on new marketing email events, such as opens or clicks.', aiMetadata: { description: 'Fires when a new marketing-email event occurs in HubSpot, optionally filtered to a single event type (sent, delivered, open, click, bounce, dropped, deferred, processed, status change, or spam report). Each event represents one email engagement record with its recipient and timestamp. Polls the email events API by timestamp.', }, type: TriggerStrategy.POLLING, props: { eventType: Property.StaticDropdown({ displayName: 'Event Type', description: 'Leave empty to trigger on every event type.', required: false, options: { disabled: false, options: [ { label: 'Sent', value: 'SENT', }, { label: 'Dropped', value: 'DROPPED', }, { label: 'Processed', value: 'PROCESSED', }, { label: 'Delivered', value: 'DELIVERED', }, { label: 'Deferred', value: 'DEFERRED', }, { label: 'Bounce', value: 'BOUNCE', }, { label: 'Open', value: 'OPEN', }, { label: 'Click', value: 'CLICK', }, { label: 'Status Change', value: 'STATUSCHANGE', }, { label: 'Spam Report', value: 'SPAMREPORT', }, ], }, }), }, async onEnable(context) { await pollingHelper.onEnable(polling, context); }, async onDisable(context) { await pollingHelper.onDisable(polling, context); }, async test(context) { return await pollingHelper.test(polling, context); }, async run(context) { return await pollingHelper.poll(polling, context); }, sampleData: {}, });