diff --git a/packages/destination-actions/src/destinations/livelike-cloud/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/livelike-cloud/__tests__/__snapshots__/snapshot.test.ts.snap deleted file mode 100644 index ac8122c6c41..00000000000 --- a/packages/destination-actions/src/destinations/livelike-cloud/__tests__/__snapshots__/snapshot.test.ts.snap +++ /dev/null @@ -1,36 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Testing snapshot for actions-livelike-cloud destination: trackEvent action - all fields 1`] = ` -Object { - "events": Array [ - Object { - "anonymous_id": "n]C0wig#f82f0li1(A", - "custom_id": "n]C0wig#f82f0li1(A", - "event_name": "n]C0wig#f82f0li1(A", - "event_type": "n]C0wig#f82f0li1(A", - "livelike_profile_id": "n]C0wig#f82f0li1(A", - "properties": Object { - "testType": "n]C0wig#f82f0li1(A", - }, - "segment_user_id": "n]C0wig#f82f0li1(A", - "timestamp": "n]C0wig#f82f0li1(A", - }, - ], -} -`; - -exports[`Testing snapshot for actions-livelike-cloud destination: trackEvent action - required fields 1`] = ` -Object { - "events": Array [ - Object { - "anonymous_id": "n]C0wig#f82f0li1(A", - "custom_id": "n]C0wig#f82f0li1(A", - "event_name": "n]C0wig#f82f0li1(A", - "event_type": "n]C0wig#f82f0li1(A", - "livelike_profile_id": "n]C0wig#f82f0li1(A", - "segment_user_id": "n]C0wig#f82f0li1(A", - "timestamp": "n]C0wig#f82f0li1(A", - }, - ], -} -`; diff --git a/packages/destination-actions/src/destinations/livelike-cloud/__tests__/index.test.ts b/packages/destination-actions/src/destinations/livelike-cloud/__tests__/index.test.ts index 0aaa886557e..f324c3df311 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/__tests__/index.test.ts @@ -1,7 +1,7 @@ import nock from 'nock' import { createTestIntegration } from '@segment/actions-core' import Definition from '../index' -import { apiBaseUrl } from '../properties' +import { apiBaseUrl } from '../constants' import { Settings } from '../generated-types' const testDestination = createTestIntegration(Definition) diff --git a/packages/destination-actions/src/destinations/livelike-cloud/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/livelike-cloud/__tests__/snapshot.test.ts deleted file mode 100644 index 4c635867dd7..00000000000 --- a/packages/destination-actions/src/destinations/livelike-cloud/__tests__/snapshot.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { createTestEvent, createTestIntegration } from '@segment/actions-core' -import { generateTestData } from '../../../lib/test-data' -import destination from '../index' -import nock from 'nock' - -const testDestination = createTestIntegration(destination) -const destinationSlug = 'actions-livelike-cloud' - -describe(`Testing snapshot for ${destinationSlug} destination:`, () => { - for (const actionSlug in destination.actions) { - it(`${actionSlug} action - required fields`, async () => { - const seedName = `${destinationSlug}#${actionSlug}` - const action = destination.actions[actionSlug] - const [eventData, settingsData] = generateTestData(seedName, destination, action, true) - - nock(/.*/).persist().get(/.*/).reply(200) - nock(/.*/).persist().post(/.*/).reply(200) - nock(/.*/).persist().put(/.*/).reply(200) - - const event = createTestEvent({ - properties: eventData - }) - - const responses = await testDestination.testAction(actionSlug, { - event: event, - mapping: event.properties, - settings: settingsData, - auth: undefined - }) - - const request = responses[0].request - const rawBody = await request.text() - - try { - const json = JSON.parse(rawBody) - expect(json).toMatchSnapshot() - return - } catch (err) { - expect(rawBody).toMatchSnapshot() - } - - expect(request.headers).toMatchSnapshot() - }) - - it(`${actionSlug} action - all fields`, async () => { - const seedName = `${destinationSlug}#${actionSlug}` - const action = destination.actions[actionSlug] - const [eventData, settingsData] = generateTestData(seedName, destination, action, false) - - nock(/.*/).persist().get(/.*/).reply(200) - nock(/.*/).persist().post(/.*/).reply(200) - nock(/.*/).persist().put(/.*/).reply(200) - - const event = createTestEvent({ - properties: eventData - }) - - const responses = await testDestination.testAction(actionSlug, { - event: event, - mapping: event.properties, - settings: settingsData, - auth: undefined - }) - - const request = responses[0].request - const rawBody = await request.text() - - try { - const json = JSON.parse(rawBody) - expect(json).toMatchSnapshot() - return - } catch (err) { - expect(rawBody).toMatchSnapshot() - } - }) - } -}) diff --git a/packages/destination-actions/src/destinations/livelike-cloud/properties.ts b/packages/destination-actions/src/destinations/livelike-cloud/constants.ts similarity index 100% rename from packages/destination-actions/src/destinations/livelike-cloud/properties.ts rename to packages/destination-actions/src/destinations/livelike-cloud/constants.ts diff --git a/packages/destination-actions/src/destinations/livelike-cloud/index.ts b/packages/destination-actions/src/destinations/livelike-cloud/index.ts index 177a08691ba..43cc8000e4d 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/index.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/index.ts @@ -1,9 +1,11 @@ import { defaultValues, DestinationDefinition } from '@segment/actions-core' import type { Settings } from './generated-types' -import { apiBaseUrl } from './properties' +import { apiBaseUrl } from './constants' import trackEvent from './trackEvent' +import syncToUserGroup from './syncToUserGroup' + const presets: DestinationDefinition['presets'] = [ { name: 'Track User Actions', @@ -80,7 +82,8 @@ const destination: DestinationDefinition = { }, presets, actions: { - trackEvent + trackEvent, + syncToUserGroup } } diff --git a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/__tests__/index.test.ts b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/__tests__/index.test.ts new file mode 100644 index 00000000000..fe4ab4da118 --- /dev/null +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/__tests__/index.test.ts @@ -0,0 +1,482 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' + +let testDestination = createTestIntegration(Destination) +const apiBaseUrl = 'https://cf-blast.livelikecdn.com/api/v1' + +describe('LivelikeCloud.syncToUserGroup', () => { + + beforeAll(async () => { + // Disables all HTTP requests + nock.disableNetConnect(); + }); + + afterAll(() => { + // Re-enable HTTP requests + nock.enableNetConnect(); + }); + + beforeEach(() => { + jest.clearAllMocks(); + nock.cleanAll(); + testDestination = createTestIntegration(Destination) + }); + + describe('Engage Audience payloads', () => { + + const mapping = { + audience_id: { '@path': '$.context.personas.computation_id'}, + audience_name: {'@path': '$.context.personas.computation_key'} , + timestamp: { '@path': '$.timestamp' }, + traits_or_properties_hidden: { + '@if': { + exists: { '@path': '$.traits' }, + then: { '@path': '$.traits' }, + else: { '@path': '$.properties' } + } + }, + additional_user_traits: { + livelike_profile_id: { + '@if': { + exists: { '@path': '$.traits.livelike_profile_id' }, + then: { '@path': '$.traits.livelike_profile_id' }, + else: { '@path': '$.properties.livelike_profile_id' } + } + }, + email: { + '@if': { + exists: { '@path': '$.traits.email' }, + then: { '@path': '$.traits.email' }, + else: { '@path': '$.properties.email' } + } + } + }, + user_id: { '@path': '$.userId'} + } + + const settings = { + clientId: 'test-client-id', + producerToken: 'test-producer-token' + } + + it('should add user to Audience with an Engage track() call', async () => { + + const engageAddAudienceTrack = createTestEvent({ + properties: { + livelike_profile_id: "122", + test_audience: true, + user_id: "900", + email: "test@test.com" + }, + timestamp: "2025-07-02T16:26:57.511Z", + context: { + __segment_internal: { + creator: "sync-worker" + }, + personas: { + computation_class: "audience", + computation_id: "aud_2zJkeVoLkrirhXup2uAPEsDLq4N", + computation_key: "test_audience", + namespace: "spa_9vACn44CYGDZNPNWDUXtMJ", + space_id: "spa_9vACn44CYGDZNPNWDUXtMJ" + }, + library: { + name: "unknown", + version: "unknown" + } + }, + messageId: "personas_2zKJ24JMRhVvIFJj4ukGOBKPeNo", + event: "Audience Entered", + receivedAt: "2025-07-02T16:27:10.584Z", + integrations: { + All: false, + LiveLike: true + }, + userId: "900", + type: "track" + }) + + engageAddAudienceTrack.traits = undefined + + const addJson = [{ + audience_id: 'aud_2zJkeVoLkrirhXup2uAPEsDLq4N', + audience_name: 'test_audience', + action: true, + timestamp: '2025-07-02T16:26:57.511Z', + livelike_profile_id: '122', + user_id: '900', + email: "test@test.com" + }] + + nock(apiBaseUrl) + .post('/applications/test-client-id/segment-audience-sync/', addJson) + .reply(200); + + const responses = await testDestination.testAction('syncToUserGroup', { + event: engageAddAudienceTrack, + settings, + mapping + }) + + expect(responses.length).toBe(1) + expect(responses[0].status).toBe(200) + }) + + + it('should remove user from Audience with an Engage track() call', async () => { + + const engageAddAudienceTrack = createTestEvent({ + properties: { + test_audience: false, + user_id: "900" + }, + timestamp: "2025-07-02T16:26:57.511Z", + context: { + __segment_internal: { + creator: "sync-worker" + }, + personas: { + computation_class: "audience", + computation_id: "aud_2zJkeVoLkrirhXup2uAPEsDLq4N", + computation_key: "test_audience", + namespace: "spa_9vACn44CYGDZNPNWDUXtMJ", + space_id: "spa_9vACn44CYGDZNPNWDUXtMJ" + }, + library: { + name: "unknown", + version: "unknown" + } + }, + messageId: "personas_2zKJ24JMRhVvIFJj4ukGOBKPeNo", + event: "Audience Entered", + receivedAt: "2025-07-02T16:27:10.584Z", + integrations: { + All: false, + LiveLike: true + }, + userId: "900", + type: "track" + }) + + engageAddAudienceTrack.traits = undefined + + const addJson = [{ + audience_id: 'aud_2zJkeVoLkrirhXup2uAPEsDLq4N', + audience_name: 'test_audience', + action: false, + timestamp: '2025-07-02T16:26:57.511Z', + user_id: '900' + }] + + nock(apiBaseUrl) + .post('/applications/test-client-id/segment-audience-sync/', addJson) + .reply(200); + + const responses = await testDestination.testAction('syncToUserGroup', { + event: engageAddAudienceTrack, + settings, + mapping + }) + + expect(responses.length).toBe(1) + expect(responses[0].status).toBe(200) + }) + }) + + describe('Non Engage payloads' , () => { + + const mapping = { + audience_id: { '@path': '$.properties.audience_id'}, + audience_name: {'@path': '$.properties.audience_name'} , + timestamp: { '@path': '$.timestamp' }, + action: { '@path': '$.properties.action' }, + traits_or_properties_hidden: { + '@if': { + exists: { '@path': '$.traits' }, + then: { '@path': '$.traits' }, + else: { '@path': '$.properties' } + } + }, + additional_user_traits: { + livelike_profile_id: { + '@if': { + exists: { '@path': '$.traits.livelike_profile_id' }, + then: { '@path': '$.traits.livelike_profile_id' }, + else: { '@path': '$.properties.livelike_profile_id' } + } + }, + email: { + '@if': { + exists: { '@path': '$.traits.email' }, + then: { '@path': '$.traits.email' }, + else: { '@path': '$.properties.email' } + } + } + }, + user_id: { '@path': '$.userId'} + } + + const settings = { + clientId: 'test-client-id', + producerToken: 'test-producer-token' + } + + it('should add user to Audience when track() call not from Engage', async () => { + + const notEngageAddAudienceTrack = createTestEvent({ + properties: { + audience_name: "test_audience", + audience_id: "test_audience_12345", + livelike_profile_id: "122", + action: true, + user_id: "900", + email: "test@test.com" + }, + timestamp: "2025-07-02T16:26:57.511Z", + context: { + library: { + name: "unknown", + version: "unknown" + } + }, + messageId: "personas_2zKJ24JMRhVvIFJj4ukGOBKPeNo", + event: "Non Engage Audience Entered", + receivedAt: "2025-07-02T16:27:10.584Z", + integrations: { + All: false, + LiveLike: true + }, + userId: "900", + type: "track" + }) + + notEngageAddAudienceTrack.traits = undefined + + const addJson = [{ + audience_id: 'test_audience_12345', + audience_name: 'test_audience', + action: true, + timestamp: '2025-07-02T16:26:57.511Z', + livelike_profile_id: '122', + user_id: '900', + email: "test@test.com" + }] + + nock(apiBaseUrl) + .post('/applications/test-client-id/segment-audience-sync/', addJson) + .reply(200); + + const responses = await testDestination.testAction('syncToUserGroup', { + event: notEngageAddAudienceTrack, + settings, + mapping + }) + + expect(responses.length).toBe(1) + expect(responses[0].status).toBe(200) + }) + + it('should remove user to Audience when track() call not from Engage', async () => { + + const notEngageAddAudienceTrack = createTestEvent({ + properties: { + audience_name: "test_audience", + audience_id: "test_audience_12345", + livelike_profile_id: "122", + action: false, + user_id: "900", + email: "test@test.com" + }, + timestamp: "2025-07-02T16:26:57.511Z", + context: { + library: { + name: "unknown", + version: "unknown" + } + }, + messageId: "personas_2zKJ24JMRhVvIFJj4ukGOBKPeNo", + event: "Non Engage Audience Entered", + receivedAt: "2025-07-02T16:27:10.584Z", + integrations: { + All: false, + LiveLike: true + }, + userId: "900", + type: "track" + }) + + notEngageAddAudienceTrack.traits = undefined + + const addJson = [{ + audience_id: 'test_audience_12345', + audience_name: 'test_audience', + action: false, + timestamp: '2025-07-02T16:26:57.511Z', + livelike_profile_id: '122', + user_id: '900', + email: "test@test.com" + }] + + nock(apiBaseUrl) + .post('/applications/test-client-id/segment-audience-sync/', addJson) + .reply(200); + + const responses = await testDestination.testAction('syncToUserGroup', { + event: notEngageAddAudienceTrack, + settings, + mapping + }) + + expect(responses.length).toBe(1) + expect(responses[0].status).toBe(200) + }) + + }) + + describe('Engage Audience payloads', () => { + + const mapping = { + audience_id: { '@path': '$.context.personas.computation_id'}, + audience_name: {'@path': '$.context.personas.computation_key'} , + timestamp: { '@path': '$.timestamp' }, + traits_or_properties_hidden: { + '@if': { + exists: { '@path': '$.traits' }, + then: { '@path': '$.traits' }, + else: { '@path': '$.properties' } + } + }, + additional_user_traits: { + livelike_profile_id: { + '@if': { + exists: { '@path': '$.traits.livelike_profile_id' }, + then: { '@path': '$.traits.livelike_profile_id' }, + else: { '@path': '$.properties.livelike_profile_id' } + } + }, + email: { + '@if': { + exists: { '@path': '$.traits.email' }, + then: { '@path': '$.traits.email' }, + else: { '@path': '$.properties.email' } + } + } + }, + user_id: { '@path': '$.userId'} + } + + const settings = { + clientId: 'test-client-id', + producerToken: 'test-producer-token' + } + + it('Batch: should add and remove users to Audience with an Engage track() call', async () => { + + const engageAddAudienceTrack1 = createTestEvent({ + properties: { + livelike_profile_id: "122", + test_audience: true, + user_id: "900", + email: "test@test.com" + }, + timestamp: "2025-07-02T16:26:57.511Z", + context: { + __segment_internal: { + creator: "sync-worker" + }, + personas: { + computation_class: "audience", + computation_id: "aud_2zJkeVoLkrirhXup2uAPEsDLq4N", + computation_key: "test_audience", + namespace: "spa_9vACn44CYGDZNPNWDUXtMJ", + space_id: "spa_9vACn44CYGDZNPNWDUXtMJ" + }, + library: { + name: "unknown", + version: "unknown" + } + }, + messageId: "personas_2zKJ24JMRhVvIFJj4ukGOBKPeNo", + event: "Audience Entered", + receivedAt: "2025-07-02T16:27:10.584Z", + integrations: { + All: false, + LiveLike: true + }, + userId: "900", + type: "track" + }) + + engageAddAudienceTrack1.traits = undefined + + const engageAddAudienceTrack2 = createTestEvent({ + properties: { + livelike_profile_id: "2122", + test_audience: false, + email: "test2@test.com" + }, + timestamp: "2025-07-02T16:26:57.511Z", + context: { + __segment_internal: { + creator: "sync-worker" + }, + personas: { + computation_class: "audience", + computation_id: "aud_2zJkeVoLkrirhXup2uAPEsDLq4N", + computation_key: "test_audience", + namespace: "spa_9vACn44CYGDZNPNWDUXtMJ", + space_id: "spa_9vACn44CYGDZNPNWDUXtMJ" + }, + library: { + name: "unknown", + version: "unknown" + } + }, + messageId: "personas_2zKJ24JMRhVvIFJj4ukGOBKPeNo", + event: "Audience Existed", + receivedAt: "2025-07-02T16:27:10.584Z", + integrations: { + All: false, + LiveLike: true + }, + userId: "2900", + type: "track" + }) + + engageAddAudienceTrack2.traits = undefined + + const batchJSON = [{ + audience_id: 'aud_2zJkeVoLkrirhXup2uAPEsDLq4N', + audience_name: 'test_audience', + action: true, + timestamp: '2025-07-02T16:26:57.511Z', + livelike_profile_id: '122', + user_id: '900', + email: "test@test.com" + }, + { + audience_id: 'aud_2zJkeVoLkrirhXup2uAPEsDLq4N', + audience_name: 'test_audience', + action: false, + timestamp: '2025-07-02T16:26:57.511Z', + livelike_profile_id: '2122', + user_id: '2900', + email: "test2@test.com" + }] + + nock(apiBaseUrl) + .post('/applications/test-client-id/segment-audience-sync/', batchJSON) + .reply(200); + + const responses = await testDestination.testBatchAction('syncToUserGroup', { + events: [engageAddAudienceTrack1, engageAddAudienceTrack2], + settings, + mapping + }) + + expect(responses.length).toBe(1) + expect(responses[0].status).toBe(200) + }) + }) +}) \ No newline at end of file diff --git a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/generated-types.ts b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/generated-types.ts new file mode 100644 index 00000000000..dc6bddc67e9 --- /dev/null +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/generated-types.ts @@ -0,0 +1,48 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * The unique identifier for the Segment Audience. + */ + audience_id: string + /** + * The name of the Segment Audience. + */ + audience_name: string + /** + * Set to true to add the user to the User Group, set to false to remove the user from the User Group. If connecting to an Engage Audience, leave this field empty. + */ + action?: boolean + /** + * The timestamp of the event. + */ + timestamp: string + /** + * Used for trait values to send to Livelike. + */ + additional_user_traits?: { + /** + * The unique LiveLike user identifier. + */ + livelike_profile_id?: string + /** + * The email address of the user. + */ + email?: string + [k: string]: unknown + } + /** + * Hidden field used to figure out if user is added or removed from an Engage Audience + */ + traits_or_properties_hidden?: { + [k: string]: unknown + } + /** + * A unique identifier for a user. + */ + user_id?: string + /** + * The number of records to process in each batch. Default is 100. + */ + batch_size?: number +} diff --git a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts new file mode 100644 index 00000000000..6ef362b4c01 --- /dev/null +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts @@ -0,0 +1,116 @@ +import { ActionDefinition } from '@segment/actions-core' +import type { Settings } from '../generated-types' +import type { Payload } from './generated-types' +import { processPayloads } from './utils' + +const action: ActionDefinition = { + title: 'Sync to User Group', + description: + 'Sync Segment user data to a user group in LiveLike. Can be used to sync Engage Audience data to LiveLike User Groups.', + defaultSubscription: 'type = "identify"', + fields: { + audience_id: { + label: 'Segment Audience ID', + type: 'string', + required: true, + description: 'The unique identifier for the Segment Audience.', + default: { + '@path': '$.context.personas.computation_id' + } + }, + audience_name: { + label: 'Segment Audience Name', + type: 'string', + required: true, + description: 'The name of the Segment Audience.', + default: { + '@path': '$.context.personas.computation_key' + } + }, + action: { + label: 'Action', + type: 'boolean', + description: + 'Set to true to add the user to the User Group, set to false to remove the user from the User Group. If connecting to an Engage Audience, leave this field empty.' + }, + timestamp: { + label: 'Timestamp', + type: 'string', + description: 'The timestamp of the event.', + required: true, + default: { '@path': '$.timestamp' } + }, + additional_user_traits: { + label: 'Additional user traits', + description: 'Used for trait values to send to Livelike.', + type: 'object', + unsafe_hidden: true, + defaultObjectUI: 'keyvalue:only', + additionalProperties: true, + properties: { + livelike_profile_id: { + label: 'LiveLike User Profile ID', + type: 'string', + description: 'The unique LiveLike user identifier.' + }, + email: { + label: 'Email', + type: 'string', + description: 'The email address of the user.' + } + }, + default: { + livelike_profile_id: { + '@if': { + exists: { '@path': '$.traits.livelike_profile_id' }, + then: { '@path': '$.traits.livelike_profile_id' }, + else: { '@path': '$.properties.livelike_profile_id' } + } + }, + email: { + '@if': { + exists: { '@path': '$.traits.email' }, + then: { '@path': '$.traits.email' }, + else: { '@path': '$.properties.email' } + } + } + } + }, + traits_or_properties_hidden: { + label: 'Traits or Properties hidden', + description: 'Hidden field used to figure out if user is added or removed from an Engage Audience', + type: 'object', + default: { + '@if': { + exists: { '@path': '$.traits' }, + then: { '@path': '$.traits' }, + else: { '@path': '$.properties' } + } + } + }, + user_id: { + label: 'User ID', + type: 'string', + description: 'A unique identifier for a user.', + default: { + '@path': '$.userId' + } + }, + batch_size: { + label: 'Batch Size', + type: 'number', + description: 'The number of records to process in each batch. Default is 100.', + default: 100, + minimum: 1, + maximum: 500 + } + }, + perform: (request, { settings, payload }) => { + return processPayloads(request, [payload], settings) + }, + performBatch: (request, { settings, payload }) => { + return processPayloads(request, payload, settings) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/types.ts b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/types.ts new file mode 100644 index 00000000000..556d1741dca --- /dev/null +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/types.ts @@ -0,0 +1,14 @@ +export interface UserGroupItem { + // required fields + audience_id: string + audience_name: string + action: boolean // true for add, false for remove + timestamp: string + + // optional fields + livelike_profile_id?: string + user_id?: string + traits_or_properties?: { + [k: string]: unknown + } +} \ No newline at end of file diff --git a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/utils.ts b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/utils.ts new file mode 100644 index 00000000000..14e6abf67c0 --- /dev/null +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/utils.ts @@ -0,0 +1,34 @@ +import { Payload } from './generated-types' +import { UserGroupItem } from './types' +import { PayloadValidationError, RequestClient } from '@segment/actions-core' +import { Settings } from '../generated-types' +import { apiBaseUrl } from '../constants' + +export function processPayloads(request: RequestClient, payloads: Payload[], settings: Settings) { + const json: UserGroupItem[] = payloads.map(processPayload) + const url = `${apiBaseUrl}/applications/${settings.clientId}/segment-audience-sync/` + return request(url, { + method: 'post', + json + }) +} + +function processPayload(payload: Payload): UserGroupItem { + const { audience_id, audience_name, action, timestamp, user_id, traits_or_properties_hidden, additional_user_traits } = payload + const actionValue = typeof action === 'boolean' ? action : traits_or_properties_hidden?.[audience_name] + + if(typeof actionValue !== 'boolean') { + throw new PayloadValidationError('Action must be a boolean value (true for add, false for remove). If connecting to an Engage Audience, leave this field empty and ensure the audience_id and audience_name field mappings are left to their default values.') + } + + const json: UserGroupItem = { + audience_id, + audience_name, + action: actionValue, + timestamp, + user_id, + ...additional_user_traits ?? {} + } + + return json +} \ No newline at end of file diff --git a/packages/destination-actions/src/destinations/livelike-cloud/trackEvent/__tests__/index.test.ts b/packages/destination-actions/src/destinations/livelike-cloud/trackEvent/__tests__/index.test.ts index 7e5ae6e1e07..c2eecfe3acc 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/trackEvent/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/trackEvent/__tests__/index.test.ts @@ -2,7 +2,7 @@ import nock from 'nock' import { createTestEvent, createTestIntegration, IntegrationError } from '@segment/actions-core' import Destination from '../../index' import { Payload } from '../generated-types' -import { apiBaseUrl } from '../../properties' +import { apiBaseUrl } from '../../constants' const testDestination = createTestIntegration(Destination) const LIVELIKE_CLIENT_ID = 'test-client-id' diff --git a/packages/destination-actions/src/destinations/livelike-cloud/trackEvent/index.ts b/packages/destination-actions/src/destinations/livelike-cloud/trackEvent/index.ts index 34634b8809b..fd75c44c88e 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/trackEvent/index.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/trackEvent/index.ts @@ -1,6 +1,6 @@ import { ActionDefinition, IntegrationError, RequestClient } from '@segment/actions-core' import type { Settings } from '../generated-types' -import { apiBaseUrl } from '../properties' +import { apiBaseUrl } from '../constants' import type { Payload } from './generated-types' const processData = async (request: RequestClient, settings: Settings, payloads: Payload[]) => {