From 904ee55e6bb759f33bf23149ea757e647eaf24e5 Mon Sep 17 00:00:00 2001 From: zhadier39 Date: Mon, 11 Sep 2023 15:01:20 +0500 Subject: [PATCH 01/15] Add unit and integration tests --- .../hyperengage/__tests__/hyperengage.test.ts | 15 ++ .../__tests__/validateInput.test.ts | 94 +++++++++++ .../destinations/hyperengage/commonFields.ts | 156 ++++++++++++++++++ .../hyperengage/generated-types.ts | 12 ++ .../hyperengage/group/__tests__/index.test.ts | 106 ++++++++++++ .../hyperengage/group/generated-types.ts | 128 ++++++++++++++ .../destinations/hyperengage/group/index.ts | 91 ++++++++++ .../identify/__tests__/index.test.ts | 110 ++++++++++++ .../hyperengage/identify/generated-types.ts | 112 +++++++++++++ .../hyperengage/identify/index.ts | 70 ++++++++ .../src/destinations/hyperengage/index.ts | 72 ++++++++ .../hyperengage/track/__tests__/index.test.ts | 87 ++++++++++ .../hyperengage/track/generated-types.ts | 108 ++++++++++++ .../destinations/hyperengage/track/index.ts | 50 ++++++ .../destinations/hyperengage/validateInput.ts | 110 ++++++++++++ 15 files changed, 1321 insertions(+) create mode 100644 packages/destination-actions/src/destinations/hyperengage/__tests__/hyperengage.test.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/commonFields.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/generated-types.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/group/index.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/identify/index.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/index.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/track/index.ts create mode 100644 packages/destination-actions/src/destinations/hyperengage/validateInput.ts diff --git a/packages/destination-actions/src/destinations/hyperengage/__tests__/hyperengage.test.ts b/packages/destination-actions/src/destinations/hyperengage/__tests__/hyperengage.test.ts new file mode 100644 index 0000000000..7c8f68aa88 --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/__tests__/hyperengage.test.ts @@ -0,0 +1,15 @@ +import { createTestIntegration } from '@segment/actions-core' +import Definition from '../index' + +export const apiKey = 'testApiKey' +export const workspaceIdentifier = 'testApiIdentifier' + +const testDestination = createTestIntegration(Definition) + +describe('Hyperengage', () => { + describe('testAuthentication', () => { + it('should validate workspaceIdentifier and apiKey', async () => { + await expect(testDestination.testAuthentication({ apiKey, workspaceIdentifier })).resolves.not.toThrowError() + }) + }) +}) diff --git a/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts b/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts new file mode 100644 index 0000000000..ab0a6d6c7b --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts @@ -0,0 +1,94 @@ +import { validateInput } from '../validateInput' + +const fakeTrackData = { + event_id: 'test-message-cz380xxe9kn', + page_title: 'Title', + event_name: 'test', + event_type: 'track', + properties: { + required: 'false' + }, + timestamp: '2023-09-11T08:06:11.192Z', + user_id: 'test', + account_id: 'testAccount' +} + +const fakeIdentifyData = { + event_id: 'test-message-cz380xxe9kn', + page_title: 'Title', + event_name: 'test', + event_type: 'identify', + name: 'testUser', + email: 'testEmail', + traits: { + required: 'false' + }, + timestamp: '2023-09-11T08:06:11.192Z', + user_id: 'test', + account_id: 'testAccount' +} + +const fakeGroupData = { + event_id: 'test-message-cz380xxe9kn', + page_title: 'Title', + event_name: 'test', + event_type: 'group', + name: 'Test account', + plan: 'temporary', + industry: 'test industry', + website: 'test website', + traits: { + required: 'false' + }, + timestamp: '2023-09-11T08:06:11.192Z', + user_id: 'test', + account_id: 'testAccount' +} + +const settings = { + workspaceIdentifier: 'testWorkspaceId', + apiKey: 'testApiKey' +} + +describe('validateInput', () => { + describe('test common payload', () => { + it('should return converted payload', () => { + const payload = validateInput(settings, fakeIdentifyData, 'user_identify') + expect(payload.api_key).toBe(settings.apiKey) + expect(payload.workspace_key).toBe(settings.workspaceIdentifier) + expect(payload.doc_encoding).toBe('UTF-8') + expect(payload.src).toBe('segment_api') + expect(payload.anonymous_id).toHaveLength(10) + }) + }) + + describe('test identify payload', () => { + it('should return converted payload', async () => { + const payload = validateInput(settings, fakeIdentifyData, 'user_identify') + expect(payload.user_id).toEqual(fakeIdentifyData.user_id) + expect(payload.traits.email).toEqual(fakeIdentifyData.email) + expect(payload.traits.name).toEqual(fakeIdentifyData.name) + expect(payload.traits).toHaveProperty('required') + }) + }) + + describe('test group payload', () => { + it('should return converted payload', async () => { + const payload = validateInput(settings, fakeGroupData, 'account_identify') + expect(payload.account_id).toEqual(fakeGroupData.account_id) + expect(payload.traits.plan_name).toEqual(fakeGroupData.plan) + expect(payload.traits.industry).toEqual(fakeGroupData.industry) + expect(payload.traits.website).toEqual(fakeGroupData.website) + expect(payload.traits).toHaveProperty('required') + }) + }) + + describe('test track payload', () => { + it('should return converted payload', async () => { + let payload = validateInput(settings, fakeGroupData, 'account_identify') + expect(payload.event_type).toEqual('account_identify') + payload = validateInput(settings, fakeTrackData, 'track') + expect(payload.event_type).toEqual('test') + }) + }) +}) diff --git a/packages/destination-actions/src/destinations/hyperengage/commonFields.ts b/packages/destination-actions/src/destinations/hyperengage/commonFields.ts new file mode 100644 index 0000000000..add0bd51f5 --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/commonFields.ts @@ -0,0 +1,156 @@ +import { ActionDefinition } from '@segment/actions-core' +import { Settings } from '../encharge/generated-types' + +export const commonFields: ActionDefinition['fields'] = { + event_id: { + type: 'string', + required: false, + description: 'The ID of the event.', + label: 'Event ID', + default: { '@path': '$.messageId' } + }, + doc_path: { + type: 'string', + required: false, + description: 'The path of the document.', + label: 'Document Path', + default: { '@path': '$.context.page.path' } + }, + doc_search: { + type: 'string', + required: false, + description: 'The search query of the document.', + label: 'Document Search', + default: { '@path': '$.context.page.search' } + }, + page_title: { + type: 'string', + required: false, + description: 'The title of the page where the event occurred.', + label: 'Page Title', + default: { '@path': '$.context.page.title' } + }, + referer: { + type: 'string', + required: false, + description: 'The referrer of the page where the event occurred.', + label: 'Referrer', + default: { '@path': '$.context.page.referrer' } + }, + url: { + type: 'string', + required: false, + description: 'The URL of the page where the event occurred.', + label: 'URL', + default: { '@path': '$.context.page.url' } + }, + user_agent: { + type: 'string', + required: false, + description: 'The user agent of the browser.', + label: 'User Agent', + default: { '@path': '$.context.userAgent' } + }, + user_language: { + type: 'string', + required: false, + description: 'The language of the browser.', + label: 'User Language', + default: { '@path': '$.context.locale' } + }, + utc_time: { + type: 'string', + required: false, + description: 'The time of the event in UTC.', + label: 'UTC Time', + default: { '@path': '$.timestamp' } + }, + utm: { + type: 'object', + required: false, + description: 'Information about the UTM parameters.', + label: 'UTM', + properties: { + source: { + label: 'Source', + description: 'The source of the campaign.', + type: 'string' + }, + medium: { + label: 'Medium', + description: 'The medium of the campaign.', + type: 'string' + }, + name: { + label: 'Name', + description: 'The name of the campaign.', + type: 'string' + }, + term: { + label: 'Term', + description: 'The term of the campaign.', + type: 'string' + }, + content: { + label: 'Content', + description: 'The content of the campaign.', + type: 'string' + } + }, + default: { + source: { '@path': '$.context.campaign.source' }, + medium: { '@path': '$.context.campaign.medium' }, + name: { '@path': '$.context.campaign.name' }, + term: { '@path': '$.context.campaign.term' }, + content: { '@path': '$.context.campaign.content' } + } + }, + screen: { + type: 'object', + required: false, + description: 'Information about the screen.', + label: 'Screen', + properties: { + height: { + label: 'Height', + description: 'The height of the screen.', + type: 'integer' + }, + width: { + label: 'Width', + description: 'The width of the screen.', + type: 'integer' + }, + density: { + label: 'Density', + description: 'The density of the screen.', + type: 'number' + } + }, + default: { + height: { '@path': '$.context.screen.height' }, + width: { '@path': '$.context.screen.width' }, + density: { '@path': '$.context.screen.density' } + } + }, + timezone: { + type: 'string', + required: false, + description: 'The timezone of the browser.', + label: 'Timezone', + default: { + '@if': { + exists: { '@path': '$.properties.timezone' }, + then: { '@path': '$.properties.timezone' }, + else: { '@path': '$.traits.timezone' } + } + } + }, + source_ip: { + type: 'string', + required: false, + description: 'The IP address of the user.', + label: 'IP Address', + default: { '@path': '$.context.ip' } + } +} diff --git a/packages/destination-actions/src/destinations/hyperengage/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/generated-types.ts new file mode 100644 index 0000000000..660b447668 --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/generated-types.ts @@ -0,0 +1,12 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Settings { + /** + * Your Hyperengage API key located in the Integration Settings page. + */ + apiKey: string + /** + * Your Hyperengage workspace identifier located in the Integration Settings page. + */ + workspaceIdentifier: string +} diff --git a/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts new file mode 100644 index 0000000000..be91bc159e --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts @@ -0,0 +1,106 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' + +const testDestination = createTestIntegration(Destination) + +beforeEach(() => nock.cleanAll()) + +const heGroupMapping = { + account_id: { + '@path': '$.groupId' + }, + name: { + '@if': { + exists: { '@path': '$.traits.name' }, + then: { '@path': '$.traits.name' }, + else: { '@path': '$.properties.name' } + } + }, + created_at: { + '@path': '$.traits.created_at' + }, + traits: { + '@path': '$.traits' + }, + plan: { + '@path': '$.traits.plan' + }, + industry: { + '@path': '$.traits.industry' + }, + trial_start: { + '@path': '$.traits.trial_start' + }, + trial_end: { + '@path': '$.traits.trial_end' + }, + website: { + '@path': '$.traits.website' + } +} + +describe('Hyperengage.group', () => { + test('Should throw an error if `account_id or` `name` is not defined', async () => { + const event = createTestEvent({ + type: 'group', + traits: { + email: 'test@company.com' + }, + groupId: 'test@test.com' + }) + + await expect( + testDestination.testAction('group', { + event, + mapping: heGroupMapping + }) + ).rejects.toThrowError() + }) + + test('Should throw an error if workspaceIdentifier or apiKey is not defined', async () => { + const event = createTestEvent({ + type: 'group', + traits: { + name: 'test' + }, + groupId: '123456' + }) + + await expect( + testDestination.testAction('group', { + event, + mapping: heGroupMapping, + settings: { + workspaceIdentifier: '', + apiKey: '' + } + }) + ).rejects.toThrowError() + }) + + test('Should send an group event to Hyperengage', async () => { + // Mock: Segment group Call + nock('https://t.jitsu.com').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true }) + + const event = createTestEvent({ + type: 'group', + traits: { + name: 'test' + }, + groupId: '123456' + }) + + const responses = await testDestination.testAction('group', { + event, + mapping: heGroupMapping, + settings: { + workspaceIdentifier: 'identifier', + apiKey: 'apiKey' + } + }) + + expect(responses.length).toBe(1) + expect(responses[0].status).toEqual(200) + }) +}) diff --git a/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts new file mode 100644 index 0000000000..7eef57a9a1 --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts @@ -0,0 +1,128 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * External identifier for the Account + */ + account_id: string + /** + * The company name + */ + name: string + /** + * The timestamp when the company was created + */ + created_at?: string + /** + * The company custom attributes + */ + traits?: { + [k: string]: unknown + } + /** + * The company plan + */ + plan?: string + /** + * The company industry + */ + industry?: string + /** + * The company trial start date + */ + trial_start?: string + /** + * The company trial end date + */ + trial_end?: string + /** + * The company website + */ + website?: string + /** + * The ID of the event. + */ + event_id?: string + /** + * The path of the document. + */ + doc_path?: string + /** + * The search query of the document. + */ + doc_search?: string + /** + * The title of the page where the event occurred. + */ + page_title?: string + /** + * The referrer of the page where the event occurred. + */ + referer?: string + /** + * The URL of the page where the event occurred. + */ + url?: string + /** + * The user agent of the browser. + */ + user_agent?: string + /** + * The language of the browser. + */ + user_language?: string + /** + * The time of the event in UTC. + */ + utc_time?: string + /** + * Information about the UTM parameters. + */ + utm?: { + /** + * The source of the campaign. + */ + source?: string + /** + * The medium of the campaign. + */ + medium?: string + /** + * The name of the campaign. + */ + name?: string + /** + * The term of the campaign. + */ + term?: string + /** + * The content of the campaign. + */ + content?: string + } + /** + * Information about the screen. + */ + screen?: { + /** + * The height of the screen. + */ + height?: number + /** + * The width of the screen. + */ + width?: number + /** + * The density of the screen. + */ + density?: number + } + /** + * The timezone of the browser. + */ + timezone?: string + /** + * The IP address of the user. + */ + source_ip?: string +} diff --git a/packages/destination-actions/src/destinations/hyperengage/group/index.ts b/packages/destination-actions/src/destinations/hyperengage/group/index.ts new file mode 100644 index 0000000000..721f44e5d4 --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/group/index.ts @@ -0,0 +1,91 @@ +import type { ActionDefinition } from '@segment/actions-core' +import type { Settings } from '../generated-types' +import type { Payload } from './generated-types' +import { validateInput } from '../validateInput' +import { commonFields } from '../commonFields' + +const action: ActionDefinition = { + title: 'Group', + description: 'Indentify accounts for Hyperengage', + defaultSubscription: 'type = "group"', + fields: { + account_id: { + type: 'string', + required: true, + description: 'External identifier for the Account', + label: 'Company id', + default: { '@path': '$.groupId' } + }, + name: { + type: 'string', + required: true, + description: 'The company name', + label: 'Company name', + default: { + '@if': { + exists: { '@path': '$.traits.name' }, + then: { '@path': '$.traits.name' }, + else: { '@path': '$.properties.name' } + } + } + }, + created_at: { + type: 'string', + required: false, + description: 'The timestamp when the company was created', + label: 'Company created at', + default: { '@path': '$.traits.created_at' } + }, + traits: { + type: 'object', + required: false, + description: 'The company custom attributes', + label: 'Company custom attributes', + default: { '@path': '$.traits' } + }, + plan: { + type: 'string', + required: false, + description: 'The company plan', + label: 'Company plan', + default: { '@path': '$.traits.plan' } + }, + industry: { + type: 'string', + required: false, + description: 'The company industry', + label: 'Company industry', + default: { '@path': '$.traits.industry' } + }, + trial_start: { + type: 'string', + required: false, + description: 'The company trial start date', + label: 'Company trial start date', + default: { '@path': '$.traits.trial_start' } + }, + trial_end: { + type: 'string', + required: false, + description: 'The company trial end date', + label: 'Company trial end date', + default: { '@path': '$.traits.trial_end' } + }, + website: { + type: 'string', + required: false, + description: 'The company website', + label: 'Company website', + default: { '@path': '$.traits.website' } + }, + ...commonFields + }, + perform: (request, data) => { + return request(`https://t.jitsu.com/api/v1/s2s/event?token=${data.settings.apiKey}`, { + method: 'post', + json: validateInput(data.settings, data.payload, 'account_identify') + }) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts new file mode 100644 index 0000000000..639b413e83 --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts @@ -0,0 +1,110 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' + +const testDestination = createTestIntegration(Destination) + +beforeEach(() => nock.cleanAll()) + +const heIdentifyMapping = { + user_id: { + '@path': '$.userId' + }, + name: { + '@if': { + exists: { '@path': '$.traits.name' }, + then: { '@path': '$.traits.name' }, + else: { '@path': '$.properties.name' } + } + }, + email: { + '@if': { + exists: { '@path': '$.traits.email' }, + then: { '@path': '$.traits.email' }, + else: { '@path': '$.properties.email' } + } + }, + created_at: { + '@path': '$.traits.created_at' + }, + traits: { + '@path': '$.traits' + } +} + +describe('Hyperengage.identify', () => { + test('Should throw an error if `user_id or` `name` is not defined', async () => { + const event = createTestEvent({ + type: 'identify', + traits: { + name: 'test', + email: 'test@company.com' + }, + properties: { + timezone: 'America/New_York' + } + }) + + await expect( + testDestination.testAction('identify', { + event, + mapping: heIdentifyMapping + }) + ).rejects.toThrowError() + }) + + test('Should throw an error if workspaceIdentifier or apiKey is not defined', async () => { + const event = createTestEvent({ + type: 'identify', + traits: { + name: 'test', + email: 'test@company.com' + }, + properties: { + timezone: 'America/New_York' + }, + userId: '123456' + }) + + await expect( + testDestination.testAction('identify', { + event, + mapping: heIdentifyMapping, + settings: { + workspaceIdentifier: '', + apiKey: '' + } + }) + ).rejects.toThrowError() + }) + + test('Should send an identify event to Hyperengage', async () => { + // Mock: Segment Identify Call + nock('https://t.jitsu.com').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true }) + + const event = createTestEvent({ + type: 'identify', + traits: { + name: 'test', + email: 'test@company.com' + }, + properties: { + timezone: 'America/New_York' + }, + userId: '123456' + }) + + const responses = await testDestination.testAction('identify', { + event, + mapping: heIdentifyMapping, + useDefaultMappings: true, + settings: { + workspaceIdentifier: 'identifier', + apiKey: 'apiKey' + } + }) + + expect(responses.length).toBe(1) + expect(responses[0].status).toEqual(200) + }) +}) diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts new file mode 100644 index 0000000000..4702b3d314 --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts @@ -0,0 +1,112 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * External identifier for the user + */ + user_id: string + /** + * The user's name + */ + name: string + /** + * The user email address + */ + email?: string + /** + * The timestamp when the user was created + */ + created_at?: string + /** + * Traits to associate with the user + */ + traits?: { + [k: string]: unknown + } + /** + * The ID of the event. + */ + event_id?: string + /** + * The path of the document. + */ + doc_path?: string + /** + * The search query of the document. + */ + doc_search?: string + /** + * The title of the page where the event occurred. + */ + page_title?: string + /** + * The referrer of the page where the event occurred. + */ + referer?: string + /** + * The URL of the page where the event occurred. + */ + url?: string + /** + * The user agent of the browser. + */ + user_agent?: string + /** + * The language of the browser. + */ + user_language?: string + /** + * The time of the event in UTC. + */ + utc_time?: string + /** + * Information about the UTM parameters. + */ + utm?: { + /** + * The source of the campaign. + */ + source?: string + /** + * The medium of the campaign. + */ + medium?: string + /** + * The name of the campaign. + */ + name?: string + /** + * The term of the campaign. + */ + term?: string + /** + * The content of the campaign. + */ + content?: string + } + /** + * Information about the screen. + */ + screen?: { + /** + * The height of the screen. + */ + height?: number + /** + * The width of the screen. + */ + width?: number + /** + * The density of the screen. + */ + density?: number + } + /** + * The timezone of the browser. + */ + timezone?: string + /** + * The IP address of the user. + */ + source_ip?: string +} diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/index.ts b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts new file mode 100644 index 0000000000..5fe588f0d0 --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts @@ -0,0 +1,70 @@ +import type { ActionDefinition } from '@segment/actions-core' +import type { Settings } from '../generated-types' +import type { Payload } from './generated-types' +import { validateInput } from '../validateInput' +import { commonFields } from '../commonFields' + +const action: ActionDefinition = { + title: 'Identify', + description: 'Identify your user for Hyperengage', + defaultSubscription: 'type = "identify"', + platform: 'cloud', + fields: { + user_id: { + type: 'string', + required: true, + description: 'External identifier for the user', + label: 'User ID', + default: { '@path': '$.userId' } + }, + name: { + type: 'string', + required: true, + description: "The user's name", + label: 'Name', + default: { + '@if': { + exists: { '@path': '$.traits.name' }, + then: { '@path': '$.traits.name' }, + else: { '@path': '$.properties.name' } + } + } + }, + email: { + type: 'string', + required: false, + description: 'The user email address', + label: 'Email address', + default: { + '@if': { + exists: { '@path': '$.traits.email' }, + then: { '@path': '$.traits.email' }, + else: { '@path': '$.properties.email' } + } + } + }, + created_at: { + type: 'string', + required: false, + description: 'The timestamp when the user was created', + label: 'Created at', + default: { '@path': '$.traits.created_at' } + }, + traits: { + type: 'object', + label: 'Traits', + description: 'Traits to associate with the user', + required: false, + default: { '@path': '$.traits' } + }, + ...commonFields + }, + perform: (request, data) => { + return request(`https://t.jitsu.com/api/v1/s2s/event?token=${data.settings.apiKey}`, { + method: 'post', + json: validateInput(data.settings, data.payload, 'user_identify') + }) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/hyperengage/index.ts b/packages/destination-actions/src/destinations/hyperengage/index.ts new file mode 100644 index 0000000000..5c5abe00f7 --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/index.ts @@ -0,0 +1,72 @@ +import type { DestinationDefinition } from '@segment/actions-core' +import type { Settings } from './generated-types' +import { IntegrationError, defaultValues } from '@segment/actions-core' +import identify from './identify' +import group from './group' +import track from './track' + +const presets: DestinationDefinition['presets'] = [ + { + name: 'Track Calls', + subscribe: 'type = "track"', + partnerAction: 'track', + mapping: defaultValues(track.fields), + type: 'automatic' + }, + { + name: 'Identify Calls', + subscribe: 'type = "identify"', + partnerAction: 'identify', + mapping: defaultValues(identify.fields), + type: 'automatic' + }, + { + name: 'Group Calls', + subscribe: 'type = "group"', + partnerAction: 'group', + mapping: defaultValues(group.fields), + type: 'automatic' + } +] + +const destination: DestinationDefinition = { + name: 'Hyperengage', + slug: 'actions-hyperengage', + mode: 'cloud', + + authentication: { + scheme: 'custom', + fields: { + apiKey: { + type: 'string', + label: 'API Key', + description: 'Your Hyperengage API key located in the Integration Settings page.', + required: true + }, + workspaceIdentifier: { + type: 'string', + label: 'Workspace Identifier', + description: 'Your Hyperengage workspace identifier located in the Integration Settings page.', + required: true + } + }, + testAuthentication: (_, { settings }) => { + if (!settings.apiKey || settings.apiKey.length === 0) { + throw new IntegrationError('API Key is required', 'Invalid API Key', 400) + } + + if (!settings.workspaceIdentifier || settings.workspaceIdentifier.length === 0) { + throw new IntegrationError('Server Token is required', 'Invalid Server Token', 400) + } + return true + } + }, + presets, + actions: { + identify, + group, + track + } +} + +export default destination diff --git a/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts new file mode 100644 index 0000000000..084a2123ad --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts @@ -0,0 +1,87 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' + +const testDestination = createTestIntegration(Destination) + +beforeEach(() => nock.cleanAll()) + +const heTrackMapping = { + event_name: { + '@path': '$.event' + }, + properties: { + '@path': '$.properties' + }, + user_id: { + '@path': '$.userId' + }, + account_id: { + '@path': '$.groupId' + } +} + +describe('Hyperengage.track', () => { + test('Should throw an error if `event_name` is not defined', async () => { + const event = createTestEvent({ + type: 'track', + properties: { + recency: 'Now' + }, + event: 'Test_Event' + }) + + await expect( + testDestination.testAction('track', { + event, + mapping: heTrackMapping + }) + ).rejects.toThrowError() + }) + + test('Should throw an error if workspaceIdentifier or apiKey is not defined', async () => { + const event = createTestEvent({ + type: 'track', + properties: { + recency: 'Now' + }, + event: 'Test_Event' + }) + + await expect( + testDestination.testAction('track', { + event, + mapping: heTrackMapping, + settings: { + workspaceIdentifier: '', + apiKey: '' + } + }) + ).rejects.toThrowError() + }) + + test('Should send an track event to Hyperengage', async () => { + // Mock: Segment track Call + nock('https://t.jitsu.com').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true }) + + const event = createTestEvent({ + type: 'track', + properties: { + recency: 'Now' + }, + event: 'Test_Event' + }) + + const responses = await testDestination.testAction('track', { + event, + mapping: heTrackMapping, + settings: { + workspaceIdentifier: 'identifier', + apiKey: 'apiKey' + } + }) + + expect(responses.length).toBe(1) + expect(responses[0].status).toEqual(200) + }) +}) diff --git a/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts new file mode 100644 index 0000000000..7b25d1e150 --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts @@ -0,0 +1,108 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * The name of the event + */ + event_name: string + /** + * The event properties + */ + properties?: { + [k: string]: unknown + } + /** + * The user id, to uniquely identify the user associated with the event + */ + user_id?: string + /** + * The account id, to uniquely identify the account associated with the user + */ + account_id?: string + /** + * The ID of the event. + */ + event_id?: string + /** + * The path of the document. + */ + doc_path?: string + /** + * The search query of the document. + */ + doc_search?: string + /** + * The title of the page where the event occurred. + */ + page_title?: string + /** + * The referrer of the page where the event occurred. + */ + referer?: string + /** + * The URL of the page where the event occurred. + */ + url?: string + /** + * The user agent of the browser. + */ + user_agent?: string + /** + * The language of the browser. + */ + user_language?: string + /** + * The time of the event in UTC. + */ + utc_time?: string + /** + * Information about the UTM parameters. + */ + utm?: { + /** + * The source of the campaign. + */ + source?: string + /** + * The medium of the campaign. + */ + medium?: string + /** + * The name of the campaign. + */ + name?: string + /** + * The term of the campaign. + */ + term?: string + /** + * The content of the campaign. + */ + content?: string + } + /** + * Information about the screen. + */ + screen?: { + /** + * The height of the screen. + */ + height?: number + /** + * The width of the screen. + */ + width?: number + /** + * The density of the screen. + */ + density?: number + } + /** + * The timezone of the browser. + */ + timezone?: string + /** + * The IP address of the user. + */ + source_ip?: string +} diff --git a/packages/destination-actions/src/destinations/hyperengage/track/index.ts b/packages/destination-actions/src/destinations/hyperengage/track/index.ts new file mode 100644 index 0000000000..24df0a88a5 --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/track/index.ts @@ -0,0 +1,50 @@ +import type { ActionDefinition } from '@segment/actions-core' +import type { Settings } from '../generated-types' +import type { Payload } from './generated-types' +import { validateInput } from '../validateInput' +import { commonFields } from '../commonFields' + +const action: ActionDefinition = { + title: 'Track', + description: 'Send an event to Hyperengage', + defaultSubscription: 'type = "track"', + fields: { + event_name: { + type: 'string', + required: true, + description: 'The name of the event', + label: 'Event name', + default: { '@path': '$.event' } + }, + properties: { + type: 'object', + required: false, + description: 'The event properties', + label: 'Event properties', + default: { '@path': '$.properties' } + }, + user_id: { + type: 'string', + required: false, + description: 'The user id, to uniquely identify the user associated with the event', + label: 'User id', + default: { '@path': '$.userId' } + }, + account_id: { + type: 'string', + required: false, + description: 'The account id, to uniquely identify the account associated with the user', + label: 'Account id', + default: { '@path': '$.groupId' } + }, + ...commonFields + }, + perform: (request, data) => { + return request(`https://t.jitsu.com/api/v1/s2s/event?token=${data.settings.apiKey}`, { + method: 'post', + json: validateInput(data.settings, data.payload, 'track') + }) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts new file mode 100644 index 0000000000..100158d15c --- /dev/null +++ b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts @@ -0,0 +1,110 @@ +import { Settings } from './generated-types' + +// Convert relevant input properties to Hyperengage properties +export const validateInput = ( + settings: Settings, + input: Record, + event_type: 'track' | 'user_identify' | 'account_identify' +): any => { + const properties: any = { + api_key: settings.apiKey, + workspace_key: settings.workspaceIdentifier, + doc_encoding: 'UTF-8', + src: 'segment_api', + screen_resolution: '0', + user_id: input?.user_id || input?.userId, + account_id: input?.account_id || input?.accountId || input?.traits?.companyId || input?.traits?.company?.id, + anonymous_id: input?.anonymousId || Math.random().toString(36).substring(2, 12), + ids: {}, + event_type: event_type, + ...input + } + delete properties.event_name + delete properties.userId + delete properties.accountId + delete properties.anonymousId + + // Get screen_resolution from the input screen width and height + if (input?.screen) { + const { width, height } = input.screen + properties.screen_resolution = `${width || 0}x${height || 0}` + properties.vp_size = `${width || 0}x${height || 0}` + delete properties.screen + } + + // Get the doc_title from the input url + if (input?.url) { + const urlPattern = new RegExp( + '^(https?:\\/\\/)?' + // validate protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // validate domain name + '((\\d{1,3}\\.){3}\\d{1,3}))' + // validate OR ip (v4) address + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // validate port and path + '(\\?[;&a-z\\d%_.~+=-]*)?' + // validate query string + '(\\#[-a-z\\d_]*)?$', + 'i' + ) + if (urlPattern.test(input.url)) { + const url = new URL(input.url as string) + properties.doc_host = url.host + } + } + + // Resolve local_tz_offset property, we can get local_tz_offset from the input context.timezone + if (input?.timezone) { + const offset = new Date().toLocaleString('en-US', { timeZone: input.timezone, timeZoneName: 'short' }).split(' ')[2] + properties.local_tz_offset = offset + delete properties.timezone + } + + // Check if event property is present, we will use it as event_type + if (input?.event_name && event_type === 'track') { + properties.event_type = input?.event_name + delete properties.event_name + } else { + properties.event_type = event_type + } + + // Validate user properties + if (event_type === 'user_identify') { + properties.traits = { + email: input?.email, + name: input?.name, + created_at: input?.created_at, + ...properties.traits + } + + // Create object if company_id is present in traits + if (input?.traits?.company) { + properties.company = { + ...input.traits.company + } + delete properties.traits.company + } + // Delete unnecessary user properties + delete properties.email + delete properties.name + delete properties.created_at + } + + // Validate account properties + if (event_type === 'account_identify') { + properties.traits = { + name: input?.name, + created_at: input?.created_at, + plan_name: input?.plan, + industry: input?.industry, + trial_start_date: input?.trial_start, + trial_expiry_date: input?.trial_end, + website: input?.website, + ...properties.traits + } + delete properties.name + delete properties.created_at + delete properties.plan + delete properties.industry + delete properties.trial_start + delete properties.trial_end + delete properties.website + } + return properties +} From 521d6584ae2497808f0f51a12c03348467bf08c0 Mon Sep 17 00:00:00 2001 From: saadhypng Date: Mon, 11 Sep 2023 19:51:08 +0500 Subject: [PATCH 02/15] Updated field descriptions for group, identify and track --- .../hyperengage/group/__tests__/index.test.ts | 6 --- .../hyperengage/group/generated-types.ts | 22 +++------ .../destinations/hyperengage/group/index.ts | 46 +++++++------------ .../hyperengage/identify/generated-types.ts | 6 +-- .../hyperengage/identify/index.ts | 10 ++-- .../hyperengage/track/generated-types.ts | 2 +- .../destinations/hyperengage/track/index.ts | 6 +-- 7 files changed, 35 insertions(+), 63 deletions(-) diff --git a/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts index be91bc159e..2e5323af6a 100644 --- a/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts @@ -29,12 +29,6 @@ const heGroupMapping = { industry: { '@path': '$.traits.industry' }, - trial_start: { - '@path': '$.traits.trial_start' - }, - trial_end: { - '@path': '$.traits.trial_end' - }, website: { '@path': '$.traits.website' } diff --git a/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts index 7eef57a9a1..d21f2095cb 100644 --- a/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts +++ b/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts @@ -2,41 +2,33 @@ export interface Payload { /** - * External identifier for the Account + * The External ID of the account to send properties for */ account_id: string /** - * The company name + * The Account name */ name: string /** - * The timestamp when the company was created + * The timestamp when the account was created */ created_at?: string /** - * The company custom attributes + * The properties of the account */ traits?: { [k: string]: unknown } /** - * The company plan + * Subscription plan the account is associated with */ plan?: string /** - * The company industry + * The account industry */ industry?: string /** - * The company trial start date - */ - trial_start?: string - /** - * The company trial end date - */ - trial_end?: string - /** - * The company website + * The account website */ website?: string /** diff --git a/packages/destination-actions/src/destinations/hyperengage/group/index.ts b/packages/destination-actions/src/destinations/hyperengage/group/index.ts index 721f44e5d4..d30030223f 100644 --- a/packages/destination-actions/src/destinations/hyperengage/group/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/group/index.ts @@ -6,21 +6,21 @@ import { commonFields } from '../commonFields' const action: ActionDefinition = { title: 'Group', - description: 'Indentify accounts for Hyperengage', + description: 'Send group calls to Hyperengage.', defaultSubscription: 'type = "group"', fields: { account_id: { type: 'string', required: true, - description: 'External identifier for the Account', - label: 'Company id', + description: 'The External ID of the account to send properties for', + label: 'Account id', default: { '@path': '$.groupId' } }, name: { type: 'string', required: true, - description: 'The company name', - label: 'Company name', + description: 'The Account name', + label: 'Account name', default: { '@if': { exists: { '@path': '$.traits.name' }, @@ -32,56 +32,42 @@ const action: ActionDefinition = { created_at: { type: 'string', required: false, - description: 'The timestamp when the company was created', - label: 'Company created at', + description: 'The timestamp when the account was created', + label: 'Account created at', default: { '@path': '$.traits.created_at' } }, traits: { type: 'object', required: false, - description: 'The company custom attributes', - label: 'Company custom attributes', + description: 'The properties of the account', + label: 'Account properties', default: { '@path': '$.traits' } }, plan: { type: 'string', required: false, - description: 'The company plan', - label: 'Company plan', + description: 'Subscription plan the account is associated with', + label: 'Account subscription plan', default: { '@path': '$.traits.plan' } }, industry: { type: 'string', required: false, - description: 'The company industry', - label: 'Company industry', + description: 'The account industry', + label: 'Account industry', default: { '@path': '$.traits.industry' } }, - trial_start: { - type: 'string', - required: false, - description: 'The company trial start date', - label: 'Company trial start date', - default: { '@path': '$.traits.trial_start' } - }, - trial_end: { - type: 'string', - required: false, - description: 'The company trial end date', - label: 'Company trial end date', - default: { '@path': '$.traits.trial_end' } - }, website: { type: 'string', required: false, - description: 'The company website', - label: 'Company website', + description: 'The account website', + label: 'Account website', default: { '@path': '$.traits.website' } }, ...commonFields }, perform: (request, data) => { - return request(`https://t.jitsu.com/api/v1/s2s/event?token=${data.settings.apiKey}`, { + return request(`https://events.hyperengage.io/api/v1/s2s/event?token=${data.settings.apiKey}`, { method: 'post', json: validateInput(data.settings, data.payload, 'account_identify') }) diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts index 4702b3d314..839882f910 100644 --- a/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts +++ b/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts @@ -2,7 +2,7 @@ export interface Payload { /** - * External identifier for the user + * The External ID of the user */ user_id: string /** @@ -10,7 +10,7 @@ export interface Payload { */ name: string /** - * The user email address + * The user's email address */ email?: string /** @@ -18,7 +18,7 @@ export interface Payload { */ created_at?: string /** - * Traits to associate with the user + * Properties to associate with the user */ traits?: { [k: string]: unknown diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/index.ts b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts index 5fe588f0d0..96f88f1dd5 100644 --- a/packages/destination-actions/src/destinations/hyperengage/identify/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts @@ -6,14 +6,14 @@ import { commonFields } from '../commonFields' const action: ActionDefinition = { title: 'Identify', - description: 'Identify your user for Hyperengage', + description: 'Send identify calls to Hyperengage.', defaultSubscription: 'type = "identify"', platform: 'cloud', fields: { user_id: { type: 'string', required: true, - description: 'External identifier for the user', + description: 'The External ID of the user', label: 'User ID', default: { '@path': '$.userId' } }, @@ -33,7 +33,7 @@ const action: ActionDefinition = { email: { type: 'string', required: false, - description: 'The user email address', + description: "The user's email address", label: 'Email address', default: { '@if': { @@ -53,14 +53,14 @@ const action: ActionDefinition = { traits: { type: 'object', label: 'Traits', - description: 'Traits to associate with the user', + description: 'Properties to associate with the user', required: false, default: { '@path': '$.traits' } }, ...commonFields }, perform: (request, data) => { - return request(`https://t.jitsu.com/api/v1/s2s/event?token=${data.settings.apiKey}`, { + return request(`https://events.hyperengage.io/api/v1/s2s/event?token=${data.settings.apiKey}`, { method: 'post', json: validateInput(data.settings, data.payload, 'user_identify') }) diff --git a/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts index 7b25d1e150..330b24e555 100644 --- a/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts +++ b/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts @@ -6,7 +6,7 @@ export interface Payload { */ event_name: string /** - * The event properties + * The properties of the track call */ properties?: { [k: string]: unknown diff --git a/packages/destination-actions/src/destinations/hyperengage/track/index.ts b/packages/destination-actions/src/destinations/hyperengage/track/index.ts index 24df0a88a5..489024bf91 100644 --- a/packages/destination-actions/src/destinations/hyperengage/track/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/track/index.ts @@ -6,7 +6,7 @@ import { commonFields } from '../commonFields' const action: ActionDefinition = { title: 'Track', - description: 'Send an event to Hyperengage', + description: 'Send track calls to Hyperengage.', defaultSubscription: 'type = "track"', fields: { event_name: { @@ -19,7 +19,7 @@ const action: ActionDefinition = { properties: { type: 'object', required: false, - description: 'The event properties', + description: 'The properties of the track call', label: 'Event properties', default: { '@path': '$.properties' } }, @@ -40,7 +40,7 @@ const action: ActionDefinition = { ...commonFields }, perform: (request, data) => { - return request(`https://t.jitsu.com/api/v1/s2s/event?token=${data.settings.apiKey}`, { + return request(`https://events.hyperengage.io/api/v1/s2s/event?token=${data.settings.apiKey}`, { method: 'post', json: validateInput(data.settings, data.payload, 'track') }) From ab472986ae01bd731f3d40f2175acd1028ff9b96 Mon Sep 17 00:00:00 2001 From: saadhypng Date: Mon, 11 Sep 2023 19:59:05 +0500 Subject: [PATCH 03/15] Updated common fields --- .../src/destinations/hyperengage/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/destination-actions/src/destinations/hyperengage/index.ts b/packages/destination-actions/src/destinations/hyperengage/index.ts index 5c5abe00f7..f51f28e14e 100644 --- a/packages/destination-actions/src/destinations/hyperengage/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/index.ts @@ -7,21 +7,21 @@ import track from './track' const presets: DestinationDefinition['presets'] = [ { - name: 'Track Calls', + name: 'Track Event', subscribe: 'type = "track"', partnerAction: 'track', mapping: defaultValues(track.fields), type: 'automatic' }, { - name: 'Identify Calls', + name: 'Identify User', subscribe: 'type = "identify"', partnerAction: 'identify', mapping: defaultValues(identify.fields), type: 'automatic' }, { - name: 'Group Calls', + name: 'Group', subscribe: 'type = "group"', partnerAction: 'group', mapping: defaultValues(group.fields), @@ -30,7 +30,7 @@ const presets: DestinationDefinition['presets'] = [ ] const destination: DestinationDefinition = { - name: 'Hyperengage', + name: 'Hyperengage (Actions)', slug: 'actions-hyperengage', mode: 'cloud', From f4832e421a47742fd4cf9430911f87927af11701 Mon Sep 17 00:00:00 2001 From: zhadier39 Date: Tue, 12 Sep 2023 15:48:45 +0500 Subject: [PATCH 04/15] Fix identify function error --- .../destination-actions/src/destinations/hyperengage/index.ts | 2 +- .../src/destinations/hyperengage/validateInput.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/destination-actions/src/destinations/hyperengage/index.ts b/packages/destination-actions/src/destinations/hyperengage/index.ts index f51f28e14e..4e752d3b5b 100644 --- a/packages/destination-actions/src/destinations/hyperengage/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/index.ts @@ -56,7 +56,7 @@ const destination: DestinationDefinition = { } if (!settings.workspaceIdentifier || settings.workspaceIdentifier.length === 0) { - throw new IntegrationError('Server Token is required', 'Invalid Server Token', 400) + throw new IntegrationError('Workspace identifier is required', 'Invalid workspace identifier', 400) } return true } diff --git a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts index 100158d15c..49ec607f93 100644 --- a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts +++ b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts @@ -1,4 +1,5 @@ import { Settings } from './generated-types' +import random from 'lodash/random' // Convert relevant input properties to Hyperengage properties export const validateInput = ( @@ -14,7 +15,7 @@ export const validateInput = ( screen_resolution: '0', user_id: input?.user_id || input?.userId, account_id: input?.account_id || input?.accountId || input?.traits?.companyId || input?.traits?.company?.id, - anonymous_id: input?.anonymousId || Math.random().toString(36).substring(2, 12), + anonymous_id: input?.anonymousId || random(1000000000, 9999999999).toString(), ids: {}, event_type: event_type, ...input From 6de967a72f0709e6c1ffb1005646ab204304f955 Mon Sep 17 00:00:00 2001 From: saadhypng Date: Wed, 27 Sep 2023 20:17:59 +0500 Subject: [PATCH 05/15] Added authentication endpoint --- .../src/destinations/hyperengage/index.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/destination-actions/src/destinations/hyperengage/index.ts b/packages/destination-actions/src/destinations/hyperengage/index.ts index 4e752d3b5b..b213dcaad0 100644 --- a/packages/destination-actions/src/destinations/hyperengage/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/index.ts @@ -1,6 +1,6 @@ import type { DestinationDefinition } from '@segment/actions-core' import type { Settings } from './generated-types' -import { IntegrationError, defaultValues } from '@segment/actions-core' +import { defaultValues } from '@segment/actions-core' import identify from './identify' import group from './group' import track from './track' @@ -50,17 +50,17 @@ const destination: DestinationDefinition = { required: true } }, - testAuthentication: (_, { settings }) => { - if (!settings.apiKey || settings.apiKey.length === 0) { - throw new IntegrationError('API Key is required', 'Invalid API Key', 400) - } - - if (!settings.workspaceIdentifier || settings.workspaceIdentifier.length === 0) { - throw new IntegrationError('Workspace identifier is required', 'Invalid workspace identifier', 400) - } - return true + testAuthentication: async (request, { settings }) => { + return await request('https://api.hyperengage.io/api/v1/verify_api_key', { + method: 'POST', + json: { + api_key: `${settings.apiKey}`, + workspace_identifier: `${settings.workspaceIdentifier}` + } + }) } }, + presets, actions: { identify, From bb11b284d16ca661d72657f39b99aa7ca7584aee Mon Sep 17 00:00:00 2001 From: zhadier39 Date: Thu, 28 Sep 2023 18:45:25 +0500 Subject: [PATCH 06/15] Revise tests to enable auth --- .../hyperengage/__tests__/hyperengage.test.ts | 17 ++++++- .../hyperengage/group/__tests__/index.test.ts | 2 +- .../identify/__tests__/index.test.ts | 2 +- .../hyperengage/identify/generated-types.ts | 4 ++ .../hyperengage/identify/index.ts | 7 +++ .../src/destinations/hyperengage/index.ts | 2 +- .../hyperengage/track/__tests__/index.test.ts | 2 +- .../audienceEnteredSFTP.types.ts | 48 +++++++++++++++++++ 8 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts diff --git a/packages/destination-actions/src/destinations/hyperengage/__tests__/hyperengage.test.ts b/packages/destination-actions/src/destinations/hyperengage/__tests__/hyperengage.test.ts index 7c8f68aa88..582fc8e332 100644 --- a/packages/destination-actions/src/destinations/hyperengage/__tests__/hyperengage.test.ts +++ b/packages/destination-actions/src/destinations/hyperengage/__tests__/hyperengage.test.ts @@ -1,14 +1,29 @@ import { createTestIntegration } from '@segment/actions-core' import Definition from '../index' +import nock from 'nock' export const apiKey = 'testApiKey' export const workspaceIdentifier = 'testApiIdentifier' const testDestination = createTestIntegration(Definition) +beforeAll(() => { + nock.disableNetConnect() +}) + +afterAll(() => { + nock.enableNetConnect() + nock.cleanAll() +}) describe('Hyperengage', () => { describe('testAuthentication', () => { - it('should validate workspaceIdentifier and apiKey', async () => { + test('should validate workspaceIdentifier and apiKey', async () => { + nock('https://api.hyperengage.io/api/v1/verify_api_key') + .post(/.*/, { + api_key: apiKey, + workspace_identifier: workspaceIdentifier + }) + .reply(200, { message: 'Mocked response' }) await expect(testDestination.testAuthentication({ apiKey, workspaceIdentifier })).resolves.not.toThrowError() }) }) diff --git a/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts index 2e5323af6a..3ce7c9e4cd 100644 --- a/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts @@ -75,7 +75,7 @@ describe('Hyperengage.group', () => { test('Should send an group event to Hyperengage', async () => { // Mock: Segment group Call - nock('https://t.jitsu.com').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true }) + nock('https://events.hyperengage.io').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true }) const event = createTestEvent({ type: 'group', diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts index 639b413e83..0d25fcf6e8 100644 --- a/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts @@ -80,7 +80,7 @@ describe('Hyperengage.identify', () => { test('Should send an identify event to Hyperengage', async () => { // Mock: Segment Identify Call - nock('https://t.jitsu.com').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true }) + nock('https://events.hyperengage.io').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true }) const event = createTestEvent({ type: 'identify', diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts index 839882f910..fe711b9e7c 100644 --- a/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts +++ b/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts @@ -13,6 +13,10 @@ export interface Payload { * The user's email address */ email?: string + /** + * The account id, to uniquely identify the account associated with the user + */ + account_id?: string /** * The timestamp when the user was created */ diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/index.ts b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts index 96f88f1dd5..1509ca20ba 100644 --- a/packages/destination-actions/src/destinations/hyperengage/identify/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts @@ -43,6 +43,13 @@ const action: ActionDefinition = { } } }, + account_id: { + type: 'string', + required: false, + description: 'The account id, to uniquely identify the account associated with the user', + label: 'Account id', + default: { '@path': '$.groupId' } + }, created_at: { type: 'string', required: false, diff --git a/packages/destination-actions/src/destinations/hyperengage/index.ts b/packages/destination-actions/src/destinations/hyperengage/index.ts index b213dcaad0..5485873741 100644 --- a/packages/destination-actions/src/destinations/hyperengage/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/index.ts @@ -52,7 +52,7 @@ const destination: DestinationDefinition = { }, testAuthentication: async (request, { settings }) => { return await request('https://api.hyperengage.io/api/v1/verify_api_key', { - method: 'POST', + method: 'post', json: { api_key: `${settings.apiKey}`, workspace_identifier: `${settings.workspaceIdentifier}` diff --git a/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts index 084a2123ad..df840579ec 100644 --- a/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts @@ -62,7 +62,7 @@ describe('Hyperengage.track', () => { test('Should send an track event to Hyperengage', async () => { // Mock: Segment track Call - nock('https://t.jitsu.com').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true }) + nock('https://events.hyperengage.io').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true }) const event = createTestEvent({ type: 'track', diff --git a/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts b/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts new file mode 100644 index 0000000000..e4fb3b830a --- /dev/null +++ b/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts @@ -0,0 +1,48 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * User credentials for establishing an SFTP connection with LiveRamp. + */ + sftp_username?: string + /** + * User credentials for establishing an SFTP connection with LiveRamp. + */ + sftp_password?: string + /** + * Path within the LiveRamp SFTP server to upload the files to. This path must exist and all subfolders must be pre-created. + */ + sftp_folder_path?: string + /** + * Identifies the user within the entered audience. + */ + audience_key: string + /** + * Additional data pertaining to the user to be written to the file. + */ + identifier_data?: { + [k: string]: unknown + } + /** + * Additional data pertaining to the user to be hashed before written to the file. Use field name **phone_number** or **email** to apply LiveRamp's specific hashing rules. + */ + unhashed_identifier_data?: { + [k: string]: unknown + } + /** + * Character used to separate tokens in the resulting file. + */ + delimiter: string + /** + * Name of the CSV file to upload for LiveRamp ingestion. + */ + filename: string + /** + * Receive events in a batch payload. This is required for LiveRamp audiences ingestion. + */ + enable_batching: boolean + /** + * Maximum number of events to include in each batch. Actual batch sizes may be lower. + */ + batch_size?: number +} From 729c2631bb8ff8132b7362b6db9536e679f6a753 Mon Sep 17 00:00:00 2001 From: zhadier39 Date: Mon, 2 Oct 2023 17:14:01 +0500 Subject: [PATCH 07/15] Update default paths for groupId. --- .../hyperengage/group/generated-types.ts | 12 +++++----- .../destinations/hyperengage/group/index.ts | 11 ++++++++-- .../hyperengage/identify/generated-types.ts | 22 +++++++++++++------ .../hyperengage/track/generated-types.ts | 18 +++++++-------- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts index d21f2095cb..bbf99b7357 100644 --- a/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts +++ b/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts @@ -10,7 +10,7 @@ export interface Payload { */ name: string /** - * The timestamp when the account was created + * The timestamp when the account was created, represented in the ISO-8601 date format. For instance, "2023-09-26T15:30:00Z". */ created_at?: string /** @@ -31,6 +31,10 @@ export interface Payload { * The account website */ website?: string + /** + * User Anonymous id + */ + anonymous_id?: string | null /** * The ID of the event. */ @@ -46,15 +50,11 @@ export interface Payload { /** * The title of the page where the event occurred. */ - page_title?: string + doc_title?: string /** * The referrer of the page where the event occurred. */ referer?: string - /** - * The URL of the page where the event occurred. - */ - url?: string /** * The user agent of the browser. */ diff --git a/packages/destination-actions/src/destinations/hyperengage/group/index.ts b/packages/destination-actions/src/destinations/hyperengage/group/index.ts index d30030223f..086020474a 100644 --- a/packages/destination-actions/src/destinations/hyperengage/group/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/group/index.ts @@ -14,7 +14,13 @@ const action: ActionDefinition = { required: true, description: 'The External ID of the account to send properties for', label: 'Account id', - default: { '@path': '$.groupId' } + default: { + '@if': { + exists: { '@path': '$.context.group_id' }, + then: { '@path': '$.context.group_id' }, + else: { '@path': '$.context.groupId' } + } + } }, name: { type: 'string', @@ -32,7 +38,8 @@ const action: ActionDefinition = { created_at: { type: 'string', required: false, - description: 'The timestamp when the account was created', + description: + 'The timestamp when the account was created, represented in the ISO-8601 date format. For instance, "2023-09-26T15:30:00Z".', label: 'Account created at', default: { '@path': '$.traits.created_at' } }, diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts index fe711b9e7c..31da9db646 100644 --- a/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts +++ b/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts @@ -8,7 +8,15 @@ export interface Payload { /** * The user's name */ - name: string + name?: string + /** + * The user's first name. This field is mandatory if you're not providing a name field + */ + first_name?: string + /** + * The user's last name. This field is mandatory if you're not providing a name field + */ + last_name?: string /** * The user's email address */ @@ -18,7 +26,7 @@ export interface Payload { */ account_id?: string /** - * The timestamp when the user was created + * The timestamp when the user was created, represented in the ISO-8601 date format. For instance, "2023-09-26T15:30:00Z". */ created_at?: string /** @@ -27,6 +35,10 @@ export interface Payload { traits?: { [k: string]: unknown } + /** + * User Anonymous id + */ + anonymous_id?: string | null /** * The ID of the event. */ @@ -42,15 +54,11 @@ export interface Payload { /** * The title of the page where the event occurred. */ - page_title?: string + doc_title?: string /** * The referrer of the page where the event occurred. */ referer?: string - /** - * The URL of the page where the event occurred. - */ - url?: string /** * The user agent of the browser. */ diff --git a/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts index 330b24e555..547da7fcc3 100644 --- a/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts +++ b/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts @@ -5,20 +5,24 @@ export interface Payload { * The name of the event */ event_name: string + /** + * The user id, to uniquely identify the user associated with the event + */ + user_id: string /** * The properties of the track call */ properties?: { [k: string]: unknown } - /** - * The user id, to uniquely identify the user associated with the event - */ - user_id?: string /** * The account id, to uniquely identify the account associated with the user */ account_id?: string + /** + * User Anonymous id + */ + anonymous_id?: string | null /** * The ID of the event. */ @@ -34,15 +38,11 @@ export interface Payload { /** * The title of the page where the event occurred. */ - page_title?: string + doc_title?: string /** * The referrer of the page where the event occurred. */ referer?: string - /** - * The URL of the page where the event occurred. - */ - url?: string /** * The user agent of the browser. */ From 557e01dbdfc442a2249b9ee79dd0130edcbbc7d8 Mon Sep 17 00:00:00 2001 From: zhadier39 Date: Mon, 2 Oct 2023 17:17:05 +0500 Subject: [PATCH 08/15] Implement recommended changes from PR #1621 --- .../__tests__/validateInput.test.ts | 1 - .../destinations/hyperengage/commonFields.ts | 23 +++++----- .../identify/__tests__/index.test.ts | 2 +- .../hyperengage/identify/index.ts | 39 ++++++++++++++-- .../src/destinations/hyperengage/index.ts | 2 +- .../destinations/hyperengage/track/index.ts | 22 ++++++---- .../destinations/hyperengage/validateInput.ts | 44 ++++++++----------- .../audienceEnteredSFTP.types.ts | 2 +- 8 files changed, 83 insertions(+), 52 deletions(-) diff --git a/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts b/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts index ab0a6d6c7b..1298d085b1 100644 --- a/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts +++ b/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts @@ -58,7 +58,6 @@ describe('validateInput', () => { expect(payload.workspace_key).toBe(settings.workspaceIdentifier) expect(payload.doc_encoding).toBe('UTF-8') expect(payload.src).toBe('segment_api') - expect(payload.anonymous_id).toHaveLength(10) }) }) diff --git a/packages/destination-actions/src/destinations/hyperengage/commonFields.ts b/packages/destination-actions/src/destinations/hyperengage/commonFields.ts index add0bd51f5..f3657c8a27 100644 --- a/packages/destination-actions/src/destinations/hyperengage/commonFields.ts +++ b/packages/destination-actions/src/destinations/hyperengage/commonFields.ts @@ -2,6 +2,14 @@ import { ActionDefinition } from '@segment/actions-core' import { Settings } from '../encharge/generated-types' export const commonFields: ActionDefinition['fields'] = { + anonymous_id: { + type: 'string', + allowNull: true, + required: false, + description: 'User Anonymous id', + label: 'Anonymous ID', + default: { '@path': '$.anonymousId' } + }, event_id: { type: 'string', required: false, @@ -23,7 +31,7 @@ export const commonFields: ActionDefinition['fields'] = { label: 'Document Search', default: { '@path': '$.context.page.search' } }, - page_title: { + doc_title: { type: 'string', required: false, description: 'The title of the page where the event occurred.', @@ -37,13 +45,6 @@ export const commonFields: ActionDefinition['fields'] = { label: 'Referrer', default: { '@path': '$.context.page.referrer' } }, - url: { - type: 'string', - required: false, - description: 'The URL of the page where the event occurred.', - label: 'URL', - default: { '@path': '$.context.page.url' } - }, user_agent: { type: 'string', required: false, @@ -140,9 +141,9 @@ export const commonFields: ActionDefinition['fields'] = { label: 'Timezone', default: { '@if': { - exists: { '@path': '$.properties.timezone' }, - then: { '@path': '$.properties.timezone' }, - else: { '@path': '$.traits.timezone' } + exists: { '@path': 'context.timezone' }, + then: { '@path': '$.context.timezone' }, + else: { '@path': '$.properties.timezone' } } } }, diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts index 0d25fcf6e8..4d43dcd4cb 100644 --- a/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts @@ -33,7 +33,7 @@ const heIdentifyMapping = { } describe('Hyperengage.identify', () => { - test('Should throw an error if `user_id or` `name` is not defined', async () => { + test('Should throw an error if `user_id` is not defined', async () => { const event = createTestEvent({ type: 'identify', traits: { diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/index.ts b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts index 1509ca20ba..49e813df7f 100644 --- a/packages/destination-actions/src/destinations/hyperengage/identify/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts @@ -19,7 +19,7 @@ const action: ActionDefinition = { }, name: { type: 'string', - required: true, + required: false, description: "The user's name", label: 'Name', default: { @@ -30,6 +30,32 @@ const action: ActionDefinition = { } } }, + first_name: { + type: 'string', + required: false, + description: "The user's first name. This field is mandatory if you're not providing a name field", + label: 'First name', + default: { + '@if': { + exists: { '@path': '$.traits.firstName' }, + then: { '@path': '$.traits.firstName' }, + else: { '@path': '$.properties.firstName' } + } + } + }, + last_name: { + type: 'string', + required: false, + description: "The user's last name. This field is mandatory if you're not providing a name field", + label: 'Last name', + default: { + '@if': { + exists: { '@path': '$.traits.lastName' }, + then: { '@path': '$.traits.lastName' }, + else: { '@path': '$.properties.lastName' } + } + } + }, email: { type: 'string', required: false, @@ -48,12 +74,19 @@ const action: ActionDefinition = { required: false, description: 'The account id, to uniquely identify the account associated with the user', label: 'Account id', - default: { '@path': '$.groupId' } + default: { + '@if': { + exists: { '@path': '$.context.group_id' }, + then: { '@path': '$.context.group_id' }, + else: { '@path': '$.context.groupId' } + } + } }, created_at: { type: 'string', required: false, - description: 'The timestamp when the user was created', + description: + 'The timestamp when the user was created, represented in the ISO-8601 date format. For instance, "2023-09-26T15:30:00Z".', label: 'Created at', default: { '@path': '$.traits.created_at' } }, diff --git a/packages/destination-actions/src/destinations/hyperengage/index.ts b/packages/destination-actions/src/destinations/hyperengage/index.ts index 5485873741..af23f8339a 100644 --- a/packages/destination-actions/src/destinations/hyperengage/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/index.ts @@ -33,7 +33,7 @@ const destination: DestinationDefinition = { name: 'Hyperengage (Actions)', slug: 'actions-hyperengage', mode: 'cloud', - + description: 'Hyperengage actions destination, to connect your product usage data from Segment to Hyperengage', authentication: { scheme: 'custom', fields: { diff --git a/packages/destination-actions/src/destinations/hyperengage/track/index.ts b/packages/destination-actions/src/destinations/hyperengage/track/index.ts index 489024bf91..305e3252b4 100644 --- a/packages/destination-actions/src/destinations/hyperengage/track/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/track/index.ts @@ -16,6 +16,13 @@ const action: ActionDefinition = { label: 'Event name', default: { '@path': '$.event' } }, + user_id: { + type: 'string', + required: true, + description: 'The user id, to uniquely identify the user associated with the event', + label: 'User id', + default: { '@path': '$.userId' } + }, properties: { type: 'object', required: false, @@ -23,19 +30,18 @@ const action: ActionDefinition = { label: 'Event properties', default: { '@path': '$.properties' } }, - user_id: { - type: 'string', - required: false, - description: 'The user id, to uniquely identify the user associated with the event', - label: 'User id', - default: { '@path': '$.userId' } - }, account_id: { type: 'string', required: false, description: 'The account id, to uniquely identify the account associated with the user', label: 'Account id', - default: { '@path': '$.groupId' } + default: { + '@if': { + exists: { '@path': '$.context.group_id' }, + then: { '@path': '$.context.group_id' }, + else: { '@path': '$.context.groupId' } + } + } }, ...commonFields }, diff --git a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts index 49ec607f93..7e10b44caa 100644 --- a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts +++ b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts @@ -1,5 +1,4 @@ import { Settings } from './generated-types' -import random from 'lodash/random' // Convert relevant input properties to Hyperengage properties export const validateInput = ( @@ -13,9 +12,7 @@ export const validateInput = ( doc_encoding: 'UTF-8', src: 'segment_api', screen_resolution: '0', - user_id: input?.user_id || input?.userId, - account_id: input?.account_id || input?.accountId || input?.traits?.companyId || input?.traits?.company?.id, - anonymous_id: input?.anonymousId || random(1000000000, 9999999999).toString(), + account_id: input?.account_id || input?.traits?.companyId || input?.traits?.company?.id, ids: {}, event_type: event_type, ...input @@ -33,23 +30,6 @@ export const validateInput = ( delete properties.screen } - // Get the doc_title from the input url - if (input?.url) { - const urlPattern = new RegExp( - '^(https?:\\/\\/)?' + // validate protocol - '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // validate domain name - '((\\d{1,3}\\.){3}\\d{1,3}))' + // validate OR ip (v4) address - '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // validate port and path - '(\\?[;&a-z\\d%_.~+=-]*)?' + // validate query string - '(\\#[-a-z\\d_]*)?$', - 'i' - ) - if (urlPattern.test(input.url)) { - const url = new URL(input.url as string) - properties.doc_host = url.host - } - } - // Resolve local_tz_offset property, we can get local_tz_offset from the input context.timezone if (input?.timezone) { const offset = new Date().toLocaleString('en-US', { timeZone: input.timezone, timeZoneName: 'short' }).split(' ')[2] @@ -67,11 +47,20 @@ export const validateInput = ( // Validate user properties if (event_type === 'user_identify') { - properties.traits = { - email: input?.email, - name: input?.name, - created_at: input?.created_at, - ...properties.traits + if (input?.name) { + properties.traits = { + email: input?.email, + name: input?.name, + created_at: input?.created_at, + ...properties.traits + } + } else if (input?.first_name || input?.last_name) { + properties.traits = { + email: input?.email, + name: `${input?.first_name} ${input?.last_name}}`, + created_at: input?.created_at, + ...properties.traits + } } // Create object if company_id is present in traits @@ -84,6 +73,8 @@ export const validateInput = ( // Delete unnecessary user properties delete properties.email delete properties.name + delete properties.first_name + delete properties.last_name delete properties.created_at } @@ -107,5 +98,6 @@ export const validateInput = ( delete properties.trial_end delete properties.website } + console.log(properties) return properties } diff --git a/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts b/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts index e4fb3b830a..dde35bd23f 100644 --- a/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts +++ b/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts @@ -14,7 +14,7 @@ export interface Payload { */ sftp_folder_path?: string /** - * Identifies the user within the entered audience. + * Unique ID that identifies members of an audience. A typical audience key might be client customer IDs, email addresses, or phone numbers. */ audience_key: string /** From e65c38d60d6fbdab80c0fdcb075a90e23ea94df6 Mon Sep 17 00:00:00 2001 From: zhadier39 Date: Mon, 2 Oct 2023 17:24:39 +0500 Subject: [PATCH 09/15] Add url field --- .../src/destinations/hyperengage/commonFields.ts | 7 +++++++ .../src/destinations/hyperengage/validateInput.ts | 3 --- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/destination-actions/src/destinations/hyperengage/commonFields.ts b/packages/destination-actions/src/destinations/hyperengage/commonFields.ts index f3657c8a27..2ff2b99722 100644 --- a/packages/destination-actions/src/destinations/hyperengage/commonFields.ts +++ b/packages/destination-actions/src/destinations/hyperengage/commonFields.ts @@ -38,6 +38,13 @@ export const commonFields: ActionDefinition['fields'] = { label: 'Page Title', default: { '@path': '$.context.page.title' } }, + url: { + type: 'string', + required: false, + description: 'The URL of the page where the event occurred.', + label: 'URL', + default: { '@path': '$.context.page.url' } + }, referer: { type: 'string', required: false, diff --git a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts index 7e10b44caa..297a7544a1 100644 --- a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts +++ b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts @@ -18,9 +18,6 @@ export const validateInput = ( ...input } delete properties.event_name - delete properties.userId - delete properties.accountId - delete properties.anonymousId // Get screen_resolution from the input screen width and height if (input?.screen) { From 0b833d455746106a52c783f1f9ec9554b367a913 Mon Sep 17 00:00:00 2001 From: zhadier39 Date: Mon, 2 Oct 2023 17:49:53 +0500 Subject: [PATCH 10/15] Resolve pathing issues and add tests/checks for first and last name fields --- .../hyperengage/group/generated-types.ts | 4 + .../destinations/hyperengage/group/index.ts | 2 +- .../identify/__tests__/index.test.ts | 97 ++++++++++++++++++- .../hyperengage/identify/generated-types.ts | 10 +- .../hyperengage/identify/index.ts | 17 ++-- .../hyperengage/track/generated-types.ts | 4 + .../destinations/hyperengage/track/index.ts | 2 +- .../destinations/hyperengage/validateInput.ts | 4 +- 8 files changed, 126 insertions(+), 14 deletions(-) diff --git a/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts index bbf99b7357..2529094d87 100644 --- a/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts +++ b/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts @@ -51,6 +51,10 @@ export interface Payload { * The title of the page where the event occurred. */ doc_title?: string + /** + * The URL of the page where the event occurred. + */ + url?: string /** * The referrer of the page where the event occurred. */ diff --git a/packages/destination-actions/src/destinations/hyperengage/group/index.ts b/packages/destination-actions/src/destinations/hyperengage/group/index.ts index 086020474a..26ae905724 100644 --- a/packages/destination-actions/src/destinations/hyperengage/group/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/group/index.ts @@ -18,7 +18,7 @@ const action: ActionDefinition = { '@if': { exists: { '@path': '$.context.group_id' }, then: { '@path': '$.context.group_id' }, - else: { '@path': '$.context.groupId' } + else: { '@path': '$.groupId' } } } }, diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts index 4d43dcd4cb..5f02a6d32a 100644 --- a/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts @@ -17,6 +17,20 @@ const heIdentifyMapping = { else: { '@path': '$.properties.name' } } }, + first_name: { + '@if': { + exists: { '@path': '$.traits.first_name' }, + then: { '@path': '$.traits.first_name' }, + else: { '@path': '$.properties.first_name' } + } + }, + last_name: { + '@if': { + exists: { '@path': '$.traits.last_name' }, + then: { '@path': '$.traits.last_name' }, + else: { '@path': '$.properties.last_name' } + } + }, email: { '@if': { exists: { '@path': '$.traits.email' }, @@ -48,11 +62,92 @@ describe('Hyperengage.identify', () => { await expect( testDestination.testAction('identify', { event, - mapping: heIdentifyMapping + mapping: heIdentifyMapping, + settings: { + workspaceIdentifier: 'identifier', + apiKey: 'apiKey' + } }) ).rejects.toThrowError() }) + test('Should throw an error if both `name` and `first_name` & `last_name` are not defined', async () => { + const event = createTestEvent({ + type: 'identify', + traits: { + email: 'test@company.com' + }, + properties: { + timezone: 'America/New_York' + }, + userId: '123456' + }) + + await expect( + testDestination.testAction('identify', { + event, + mapping: heIdentifyMapping, + settings: { + workspaceIdentifier: 'identifier', + apiKey: 'apiKey' + } + }) + ).rejects.toThrowError() + }) + + test('Should not throw error if name is defined and first and last name are not', async () => { + nock('https://events.hyperengage.io').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true }) + const event = createTestEvent({ + type: 'identify', + traits: { + name: 'test', + email: 'test@company.com' + }, + properties: { + timezone: 'America/New_York' + }, + userId: '123456' + }) + + await expect( + testDestination.testAction('identify', { + event, + mapping: heIdentifyMapping, + settings: { + workspaceIdentifier: 'identifier', + apiKey: 'apiKey' + } + }) + ).resolves.not.toThrowError() + }) + + test('Should not throw error if first_name and last_name are defined and name is not', async () => { + nock('https://events.hyperengage.io').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true }) + const event = createTestEvent({ + type: 'identify', + traits: { + first_name: 'test', + last_name: 'test', + email: 'test@company.com' + }, + properties: { + timezone: 'America/New_York' + }, + userId: '123456' + }) + + await expect( + testDestination.testAction('identify', { + event, + mapping: heIdentifyMapping, + settings: { + workspaceIdentifier: 'identifier', + apiKey: 'apiKey' + } + }) + ).resolves.not.toThrowError() + }) + test('Should throw an error if workspaceIdentifier or apiKey is not defined', async () => { const event = createTestEvent({ type: 'identify', diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts index 31da9db646..ccbb2d14da 100644 --- a/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts +++ b/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts @@ -8,15 +8,15 @@ export interface Payload { /** * The user's name */ - name?: string + name?: string | null /** * The user's first name. This field is mandatory if you're not providing a name field */ - first_name?: string + first_name?: string | null /** * The user's last name. This field is mandatory if you're not providing a name field */ - last_name?: string + last_name?: string | null /** * The user's email address */ @@ -55,6 +55,10 @@ export interface Payload { * The title of the page where the event occurred. */ doc_title?: string + /** + * The URL of the page where the event occurred. + */ + url?: string /** * The referrer of the page where the event occurred. */ diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/index.ts b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts index 49e813df7f..4acd8d5fa8 100644 --- a/packages/destination-actions/src/destinations/hyperengage/identify/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts @@ -21,6 +21,7 @@ const action: ActionDefinition = { type: 'string', required: false, description: "The user's name", + allowNull: true, label: 'Name', default: { '@if': { @@ -33,26 +34,28 @@ const action: ActionDefinition = { first_name: { type: 'string', required: false, + allowNull: true, description: "The user's first name. This field is mandatory if you're not providing a name field", label: 'First name', default: { '@if': { - exists: { '@path': '$.traits.firstName' }, - then: { '@path': '$.traits.firstName' }, - else: { '@path': '$.properties.firstName' } + exists: { '@path': '$.traits.first_name' }, + then: { '@path': '$.traits.first_name' }, + else: { '@path': '$.properties.first_name' } } } }, last_name: { type: 'string', required: false, + allowNull: true, description: "The user's last name. This field is mandatory if you're not providing a name field", label: 'Last name', default: { '@if': { - exists: { '@path': '$.traits.lastName' }, - then: { '@path': '$.traits.lastName' }, - else: { '@path': '$.properties.lastName' } + exists: { '@path': '$.traits.last_name' }, + then: { '@path': '$.traits.last_name' }, + else: { '@path': '$.properties.last_name' } } } }, @@ -78,7 +81,7 @@ const action: ActionDefinition = { '@if': { exists: { '@path': '$.context.group_id' }, then: { '@path': '$.context.group_id' }, - else: { '@path': '$.context.groupId' } + else: { '@path': '$.groupId' } } } }, diff --git a/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts index 547da7fcc3..f05ca21a4a 100644 --- a/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts +++ b/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts @@ -39,6 +39,10 @@ export interface Payload { * The title of the page where the event occurred. */ doc_title?: string + /** + * The URL of the page where the event occurred. + */ + url?: string /** * The referrer of the page where the event occurred. */ diff --git a/packages/destination-actions/src/destinations/hyperengage/track/index.ts b/packages/destination-actions/src/destinations/hyperengage/track/index.ts index 305e3252b4..9565ede19c 100644 --- a/packages/destination-actions/src/destinations/hyperengage/track/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/track/index.ts @@ -39,7 +39,7 @@ const action: ActionDefinition = { '@if': { exists: { '@path': '$.context.group_id' }, then: { '@path': '$.context.group_id' }, - else: { '@path': '$.context.groupId' } + else: { '@path': '$.groupId' } } } }, diff --git a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts index 297a7544a1..c66b859f84 100644 --- a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts +++ b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts @@ -58,6 +58,8 @@ export const validateInput = ( created_at: input?.created_at, ...properties.traits } + } else { + throw new Error('Either name, or first_name and last_name must be provided.') } // Create object if company_id is present in traits @@ -95,6 +97,6 @@ export const validateInput = ( delete properties.trial_end delete properties.website } - console.log(properties) + return properties } From 1c13eeff02222669c595cb827c32907edb3ad56d Mon Sep 17 00:00:00 2001 From: zhadier39 Date: Tue, 3 Oct 2023 15:27:31 +0500 Subject: [PATCH 11/15] Resolve test issues, payload validation error, and correct context default --- .../src/destinations/hyperengage/commonFields.ts | 2 +- .../hyperengage/group/__tests__/index.test.ts | 10 ++++++++-- .../hyperengage/identify/__tests__/index.test.ts | 10 ++++++++-- .../hyperengage/track/__tests__/index.test.ts | 10 ++++++++-- .../src/destinations/hyperengage/validateInput.ts | 5 ++++- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/packages/destination-actions/src/destinations/hyperengage/commonFields.ts b/packages/destination-actions/src/destinations/hyperengage/commonFields.ts index 2ff2b99722..60a4ecce9b 100644 --- a/packages/destination-actions/src/destinations/hyperengage/commonFields.ts +++ b/packages/destination-actions/src/destinations/hyperengage/commonFields.ts @@ -148,7 +148,7 @@ export const commonFields: ActionDefinition['fields'] = { label: 'Timezone', default: { '@if': { - exists: { '@path': 'context.timezone' }, + exists: { '@path': '$.context.timezone' }, then: { '@path': '$.context.timezone' }, else: { '@path': '$.properties.timezone' } } diff --git a/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts index 3ce7c9e4cd..ce30720874 100644 --- a/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts @@ -4,7 +4,14 @@ import Destination from '../../index' const testDestination = createTestIntegration(Destination) -beforeEach(() => nock.cleanAll()) +beforeAll(() => { + nock.disableNetConnect() +}) + +afterAll(() => { + nock.enableNetConnect() + nock.cleanAll() +}) const heGroupMapping = { account_id: { @@ -94,7 +101,6 @@ describe('Hyperengage.group', () => { } }) - expect(responses.length).toBe(1) expect(responses[0].status).toEqual(200) }) }) diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts index 5f02a6d32a..136cdd94a0 100644 --- a/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts @@ -4,7 +4,14 @@ import Destination from '../../index' const testDestination = createTestIntegration(Destination) -beforeEach(() => nock.cleanAll()) +beforeAll(() => { + nock.disableNetConnect() +}) + +afterAll(() => { + nock.enableNetConnect() + nock.cleanAll() +}) const heIdentifyMapping = { user_id: { @@ -199,7 +206,6 @@ describe('Hyperengage.identify', () => { } }) - expect(responses.length).toBe(1) expect(responses[0].status).toEqual(200) }) }) diff --git a/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts index df840579ec..ab8977280b 100644 --- a/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts @@ -4,7 +4,14 @@ import Destination from '../../index' const testDestination = createTestIntegration(Destination) -beforeEach(() => nock.cleanAll()) +beforeAll(() => { + nock.disableNetConnect() +}) + +afterAll(() => { + nock.enableNetConnect() + nock.cleanAll() +}) const heTrackMapping = { event_name: { @@ -81,7 +88,6 @@ describe('Hyperengage.track', () => { } }) - expect(responses.length).toBe(1) expect(responses[0].status).toEqual(200) }) }) diff --git a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts index c66b859f84..770b52a320 100644 --- a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts +++ b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts @@ -1,4 +1,7 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { Settings } from './generated-types' +import { PayloadValidationError } from '@segment/actions-core' // Convert relevant input properties to Hyperengage properties export const validateInput = ( @@ -59,7 +62,7 @@ export const validateInput = ( ...properties.traits } } else { - throw new Error('Either name, or first_name and last_name must be provided.') + throw new PayloadValidationError('Either name, or first_name and last_name must be provided.') } // Create object if company_id is present in traits From b76a78cfdb363d044c22e745b39053203b90076b Mon Sep 17 00:00:00 2001 From: zhadier39 Date: Sat, 18 Nov 2023 16:43:40 +0500 Subject: [PATCH 12/15] Fix no user_id field in group call and timezone offset bug --- .../hyperengage/group/generated-types.ts | 4 ++++ .../destinations/hyperengage/group/index.ts | 22 +++++++++++++++++-- .../hyperengage/identify/index.ts | 8 ++++++- .../hyperengage/track/generated-types.ts | 8 +++---- .../destinations/hyperengage/track/index.ts | 18 +++++++-------- .../destinations/hyperengage/validateInput.ts | 7 ++++-- 6 files changed, 49 insertions(+), 18 deletions(-) diff --git a/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts index 2529094d87..880ae08712 100644 --- a/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts +++ b/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts @@ -5,6 +5,10 @@ export interface Payload { * The External ID of the account to send properties for */ account_id: string + /** + * The ID associated with the user + */ + user_id?: string /** * The Account name */ diff --git a/packages/destination-actions/src/destinations/hyperengage/group/index.ts b/packages/destination-actions/src/destinations/hyperengage/group/index.ts index 26ae905724..54cf68aa2f 100644 --- a/packages/destination-actions/src/destinations/hyperengage/group/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/group/index.ts @@ -22,6 +22,12 @@ const action: ActionDefinition = { } } }, + user_id: { + type: 'string', + description: 'The ID associated with the user', + label: 'User ID', + default: { '@path': '$.userId' } + }, name: { type: 'string', required: true, @@ -41,7 +47,13 @@ const action: ActionDefinition = { description: 'The timestamp when the account was created, represented in the ISO-8601 date format. For instance, "2023-09-26T15:30:00Z".', label: 'Account created at', - default: { '@path': '$.traits.created_at' } + default: { + '@if': { + exists: { '@path': '$.traits.created_at' }, + then: { '@path': '$.traits.created_at' }, + else: { '@path': '$.traits.createdAt' } + } + } }, traits: { type: 'object', @@ -55,7 +67,13 @@ const action: ActionDefinition = { required: false, description: 'Subscription plan the account is associated with', label: 'Account subscription plan', - default: { '@path': '$.traits.plan' } + default: { + '@if': { + exists: { '@path': '$.traits.plan' }, + then: { '@path': '$.traits.plan' }, + else: { '@path': '$.traits.plan_name' } + } + } }, industry: { type: 'string', diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/index.ts b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts index 4acd8d5fa8..344143e373 100644 --- a/packages/destination-actions/src/destinations/hyperengage/identify/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts @@ -91,7 +91,13 @@ const action: ActionDefinition = { description: 'The timestamp when the user was created, represented in the ISO-8601 date format. For instance, "2023-09-26T15:30:00Z".', label: 'Created at', - default: { '@path': '$.traits.created_at' } + default: { + '@if': { + exists: { '@path': '$.traits.created_at' }, + then: { '@path': '$.traits.created_at' }, + else: { '@path': '$.traits.createdAt' } + } + } }, traits: { type: 'object', diff --git a/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts index f05ca21a4a..c11f816ded 100644 --- a/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts +++ b/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts @@ -9,16 +9,16 @@ export interface Payload { * The user id, to uniquely identify the user associated with the event */ user_id: string + /** + * The account id, to uniquely identify the account associated with the user + */ + account_id?: string /** * The properties of the track call */ properties?: { [k: string]: unknown } - /** - * The account id, to uniquely identify the account associated with the user - */ - account_id?: string /** * User Anonymous id */ diff --git a/packages/destination-actions/src/destinations/hyperengage/track/index.ts b/packages/destination-actions/src/destinations/hyperengage/track/index.ts index 9565ede19c..495803544b 100644 --- a/packages/destination-actions/src/destinations/hyperengage/track/index.ts +++ b/packages/destination-actions/src/destinations/hyperengage/track/index.ts @@ -23,13 +23,6 @@ const action: ActionDefinition = { label: 'User id', default: { '@path': '$.userId' } }, - properties: { - type: 'object', - required: false, - description: 'The properties of the track call', - label: 'Event properties', - default: { '@path': '$.properties' } - }, account_id: { type: 'string', required: false, @@ -37,12 +30,19 @@ const action: ActionDefinition = { label: 'Account id', default: { '@if': { - exists: { '@path': '$.context.group_id' }, - then: { '@path': '$.context.group_id' }, + exists: { '@path': '$.context.groupId' }, + then: { '@path': '$.context.groupId' }, else: { '@path': '$.groupId' } } } }, + properties: { + type: 'object', + required: false, + description: 'The properties of the track call', + label: 'Event properties', + default: { '@path': '$.properties' } + }, ...commonFields }, perform: (request, data) => { diff --git a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts index 770b52a320..4303f63bbc 100644 --- a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts +++ b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts @@ -32,8 +32,11 @@ export const validateInput = ( // Resolve local_tz_offset property, we can get local_tz_offset from the input context.timezone if (input?.timezone) { - const offset = new Date().toLocaleString('en-US', { timeZone: input.timezone, timeZoneName: 'short' }).split(' ')[2] - properties.local_tz_offset = offset + const offset = new Date() + .toLocaleString('en-US', { timeZone: input.timezone, timeZoneName: 'shortOffset' }) + .split(' ')[3] + .slice(3) + properties.local_tz_offset = parseInt(offset) * 60 delete properties.timezone } From a7fd188b74a07397094845ac129db1805029928b Mon Sep 17 00:00:00 2001 From: zhadier39 Date: Sat, 18 Nov 2023 17:02:29 +0500 Subject: [PATCH 13/15] Add tests for new functionality --- .../destinations/hyperengage/__tests__/validateInput.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts b/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts index 1298d085b1..00417afb92 100644 --- a/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts +++ b/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts @@ -41,6 +41,7 @@ const fakeGroupData = { required: 'false' }, timestamp: '2023-09-11T08:06:11.192Z', + timezone: 'Europe/Amsterdam', user_id: 'test', account_id: 'testAccount' } @@ -75,10 +76,12 @@ describe('validateInput', () => { it('should return converted payload', async () => { const payload = validateInput(settings, fakeGroupData, 'account_identify') expect(payload.account_id).toEqual(fakeGroupData.account_id) + expect(payload.user_id).toEqual(fakeGroupData.user_id) expect(payload.traits.plan_name).toEqual(fakeGroupData.plan) expect(payload.traits.industry).toEqual(fakeGroupData.industry) expect(payload.traits.website).toEqual(fakeGroupData.website) expect(payload.traits).toHaveProperty('required') + expect(payload.local_tz_offset).toEqual(60) }) }) From fdde21dc77cc25414cfcfddfae9307db3f9f6552 Mon Sep 17 00:00:00 2001 From: zhadier39 <113626827+zhadier39@users.noreply.github.com> Date: Wed, 22 Nov 2023 12:57:10 +0000 Subject: [PATCH 14/15] Delete packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts Remove auto generated types file on liveramp platform --- .../audienceEnteredSFTP.types.ts | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts diff --git a/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts b/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts deleted file mode 100644 index dde35bd23f..0000000000 --- a/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts +++ /dev/null @@ -1,48 +0,0 @@ -// Generated file. DO NOT MODIFY IT BY HAND. - -export interface Payload { - /** - * User credentials for establishing an SFTP connection with LiveRamp. - */ - sftp_username?: string - /** - * User credentials for establishing an SFTP connection with LiveRamp. - */ - sftp_password?: string - /** - * Path within the LiveRamp SFTP server to upload the files to. This path must exist and all subfolders must be pre-created. - */ - sftp_folder_path?: string - /** - * Unique ID that identifies members of an audience. A typical audience key might be client customer IDs, email addresses, or phone numbers. - */ - audience_key: string - /** - * Additional data pertaining to the user to be written to the file. - */ - identifier_data?: { - [k: string]: unknown - } - /** - * Additional data pertaining to the user to be hashed before written to the file. Use field name **phone_number** or **email** to apply LiveRamp's specific hashing rules. - */ - unhashed_identifier_data?: { - [k: string]: unknown - } - /** - * Character used to separate tokens in the resulting file. - */ - delimiter: string - /** - * Name of the CSV file to upload for LiveRamp ingestion. - */ - filename: string - /** - * Receive events in a batch payload. This is required for LiveRamp audiences ingestion. - */ - enable_batching: boolean - /** - * Maximum number of events to include in each batch. Actual batch sizes may be lower. - */ - batch_size?: number -} From 90f7e36d7e269b1c941e9ddf85ff3c8f7c91654d Mon Sep 17 00:00:00 2001 From: zhadier39 Date: Wed, 22 Nov 2023 18:41:11 +0500 Subject: [PATCH 15/15] Fix ts error with timeZoneName --- .../src/destinations/hyperengage/validateInput.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts index 4303f63bbc..0e22c727d8 100644 --- a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts +++ b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts @@ -33,7 +33,7 @@ export const validateInput = ( // Resolve local_tz_offset property, we can get local_tz_offset from the input context.timezone if (input?.timezone) { const offset = new Date() - .toLocaleString('en-US', { timeZone: input.timezone, timeZoneName: 'shortOffset' }) + .toLocaleString('en-US', { timeZone: input.timezone, timeZoneName: 'short' }) .split(' ')[3] .slice(3) properties.local_tz_offset = parseInt(offset) * 60