From b331f910688ca43beb29717cb4ccca4fb696fdcf Mon Sep 17 00:00:00 2001 From: Joe Ayoub Date: Wed, 16 Jul 2025 13:43:09 +0100 Subject: [PATCH 1/5] STRATCONN-6039 [Livelike] - new Action --- .../__snapshots__/snapshot.test.ts.snap | 36 --- .../livelike-cloud/__tests__/snapshot.test.ts | 77 ------ .../src/destinations/livelike-cloud/index.ts | 5 +- .../syncToUserGroup/__tests__/index.test.ts | 251 ++++++++++++++++++ .../syncToUserGroup/generated-types.ts | 13 + .../livelike-cloud/syncToUserGroup/index.ts | 114 ++++++++ .../livelike-cloud/syncToUserGroup/types.ts | 12 + 7 files changed, 394 insertions(+), 114 deletions(-) delete mode 100644 packages/destination-actions/src/destinations/livelike-cloud/__tests__/__snapshots__/snapshot.test.ts.snap delete mode 100644 packages/destination-actions/src/destinations/livelike-cloud/__tests__/snapshot.test.ts create mode 100644 packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/__tests__/index.test.ts create mode 100644 packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/generated-types.ts create mode 100644 packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts create mode 100644 packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/types.ts 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__/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/index.ts b/packages/destination-actions/src/destinations/livelike-cloud/index.ts index 177a08691ba..b1fdd97c669 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/index.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/index.ts @@ -4,6 +4,8 @@ import { apiBaseUrl } from './properties' 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..03fdb7e7e27 --- /dev/null +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/__tests__/index.test.ts @@ -0,0 +1,251 @@ +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: { + '@if': { + exists: { '@path': '$.traits' }, + then: { '@path': '$.traits' }, + else: { '@path': '$.properties' } + } + }, + livelike_profile_id: { + '@if': { + exists: {'@path': '$.traits.livelike_profile_id'}, + then: {'@path': '$.traits.livelike_profile_id' }, + else: {'@path': '$.properties.livelike_profile_id'} + } + }, + user_id: { '@path': '$.userId'}, + user_group_id: { + '@if': { + exists: {'@path': '$.traits.user_group_id'}, + then: {'@path': '$.traits.user_group_id' }, + else: {'@path': '$.properties.user_group_id'} + } + } + } + + 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: { + audience_key: "test_audience", + livelike_profile_id: "122", + test_audience: true, + user_group_id: "456", + 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: true, + timestamp: '2025-07-02T16:26:57.511Z', + livelike_profile_id: '122', + user_id: '900', + user_group_id: '456' + } + + 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 identify() call', async () => { + + const engageRemoveAudienceIdentify = createTestEvent({ + traits: { + audience_key: "test_audience", + livelike_profile_id: "122", + test_audience: false, + user_group_id: "456", + 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: "identify" + }) + + engageRemoveAudienceIdentify.properties = undefined + + const removeJson = { + audience_id: 'aud_2zJkeVoLkrirhXup2uAPEsDLq4N', + audience_name: 'test_audience', + action: false, + timestamp: '2025-07-02T16:26:57.511Z', + livelike_profile_id: '122', + user_id: '900', + user_group_id: '456' + } + + nock(apiBaseUrl) + .post('/applications/test-client-id/segment-audience-sync/', removeJson) + .reply(200); + + const responses = await testDestination.testAction('syncToUserGroup', + { + event: engageRemoveAudienceIdentify, + settings, + mapping + } + ) + + expect(responses.length).toBe(1) + expect(responses[0].status).toBe(200) + }) + }) + + describe('Non Engage payloads' , () => { + it('should remove user from Audience with a non Engage payload', async () => { + + const settings = { + clientId: 'test-client-id', + producerToken: 'test-producer-token' + } + + const nonEngageAddTrack = createTestEvent({ + properties: { + audience_id: "custom_audience_id", + audience_name: "custom_audience_name", + livelike_profile_id: "livelike_profile_id_1", + action: true + }, + timestamp: "2025-07-02T16:26:57.511Z", + messageId: "personas_2zKJ24JMRhVvIFJj4ukGOBKPeNo", + event: "Added To Custom User Group", + receivedAt: "2025-07-02T16:27:10.584Z", + userId: "900", + type: "track" + }) + + const nonEngageJson = { + audience_id: 'custom_audience_id', + audience_name: 'custom_audience_name', + action: true, + timestamp: '2025-07-02T16:26:57.511Z', + livelike_profile_id: 'livelike_profile_id_1', + user_id: '900' + } + + const nonEngageMapping = { + audience_id: { '@path': '$.properties.audience_id'}, + audience_name: {'@path': '$.properties.audience_name'} , + action: { '@path': '$.properties.action' }, + timestamp: { '@path': '$.timestamp' }, + traits_or_properties: { '@path': '$.properties' }, + livelike_profile_id: {'@path': '$.properties.livelike_profile_id'}, + user_id: { '@path': '$.userId'}, + user_group_id: {'@path': '$.properties.user_group_id'} + } + + nock(apiBaseUrl) + .post('/applications/test-client-id/segment-audience-sync/', nonEngageJson) + .reply(200); + + const responses = await testDestination.testAction('syncToUserGroup', + { + event: nonEngageAddTrack, + settings, + mapping: nonEngageMapping + } + ) + + 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..0a6988bb37f --- /dev/null +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/generated-types.ts @@ -0,0 +1,13 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + audience_id: string + audience_name: string + action: boolean // true for add, false for remove + timestamp: string // optional, defaults to current time + + livelike_profile_id?: string + user_id?: string + user_group_id?: string + traits_or_properties?: Record +} 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..6eb4d670626 --- /dev/null +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts @@ -0,0 +1,114 @@ +import { ActionDefinition, PayloadValidationError } from '@segment/actions-core' +import type { Settings } from '../generated-types' +import type { Payload } from './generated-types' +import { apiBaseUrl } from '../properties' +import { UserGroupJSON } from './types' + +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' } + }, + traits_or_properties: { + label: 'Traits or Properties', + description: 'Hidden fields used to figure out if user is added or removed from an Engage Audience', + type: 'object', + unsafe_hidden: true, + default: { + '@if': { + exists: { '@path': '$.traits' }, + then: { '@path': '$.traits' }, + else: { '@path': '$.properties' } + } + } + }, + livelike_profile_id: { + label: 'LiveLike User Profile ID', + type: 'string', + description: 'The unique LiveLike user identifier.', + default: { + '@if': { + exists: {'@path': '$.traits.livelike_profile_id'}, + then: {'@path': '$.traits.livelike_profile_id' }, + else: {'@path': '$.properties.livelike_profile_id'} + } + } + }, + user_id: { + label: 'User ID', + type: 'string', + description: 'A unique identifier for a user.', + default: { + '@path': '$.userId' + } + }, + user_group_id: { + label: 'User Group ID', + type: 'string', + description: 'The unique identifier for the User Group in LiveLike.', + default: { + '@if': { + exists: {'@path': '$.traits.user_group_id'}, + then: {'@path': '$.traits.user_group_id' }, + else: {'@path': '$.properties.user_group_id'} + } + } + } + }, + perform: (request, { settings, payload }) => { + const url = `${apiBaseUrl}/applications/${settings.clientId}/segment-audience-sync/` + const { audience_id, audience_name, action, timestamp, livelike_profile_id, user_id, user_group_id, traits_or_properties } = payload + const actionValue = typeof action === 'boolean' ? action : traits_or_properties?.[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: UserGroupJSON = { + audience_id, + audience_name, + action: actionValue, + timestamp, + livelike_profile_id, + user_id, + user_group_id + } + + return request(url, { + method: 'post', + json + }) + } +} + +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..512e581ada9 --- /dev/null +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/types.ts @@ -0,0 +1,12 @@ +export interface UserGroupJSON { + // 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 + user_group_id?: string +} \ No newline at end of file From c0a2528ed7878905b482f1a5250751bf320e4aef Mon Sep 17 00:00:00 2001 From: Joe Ayoub Date: Thu, 24 Jul 2025 14:28:21 +0100 Subject: [PATCH 2/5] changes - more to do --- .../syncToUserGroup/generated-types.ts | 41 +++++++++--- .../livelike-cloud/syncToUserGroup/index.ts | 63 ++++++++++--------- .../livelike-cloud/syncToUserGroup/types.ts | 4 +- 3 files changed, 69 insertions(+), 39 deletions(-) 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 index 0a6988bb37f..9a849615068 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/generated-types.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/generated-types.ts @@ -1,13 +1,38 @@ // Generated file. DO NOT MODIFY IT BY HAND. export interface Payload { - audience_id: string - audience_name: string - action: boolean // true for add, false for remove - timestamp: string // optional, defaults to current time - + /** + * 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 + /** + * Hidden fields used to figure out if user is added or removed from an Engage Audience + */ + traits_or_properties: { + /** + * The unique LiveLike user identifier. + */ livelike_profile_id?: string - user_id?: string - user_group_id?: string - traits_or_properties?: Record + /** + * The email address of the user. + */ + email?: string + [k: string]: unknown + } + /** + * A unique identifier for a user. + */ + user_id?: string } diff --git a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts index 6eb4d670626..5bc0469e5aa 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts @@ -44,23 +44,35 @@ const action: ActionDefinition = { description: 'Hidden fields used to figure out if user is added or removed from an Engage Audience', type: 'object', unsafe_hidden: true, - default: { - '@if': { - exists: { '@path': '$.traits' }, - then: { '@path': '$.traits' }, - else: { '@path': '$.properties' } + defaultObjectUI: 'keyvalue', + additionalProperties: true, + required: 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.' } - } - }, - livelike_profile_id: { - label: 'LiveLike User Profile ID', - type: 'string', - description: 'The unique LiveLike user identifier.', + }, default: { - '@if': { - exists: {'@path': '$.traits.livelike_profile_id'}, - then: {'@path': '$.traits.livelike_profile_id' }, - else: {'@path': '$.properties.livelike_profile_id'} + 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' } + } } } }, @@ -71,25 +83,16 @@ const action: ActionDefinition = { default: { '@path': '$.userId' } - }, - user_group_id: { - label: 'User Group ID', - type: 'string', - description: 'The unique identifier for the User Group in LiveLike.', - default: { - '@if': { - exists: {'@path': '$.traits.user_group_id'}, - then: {'@path': '$.traits.user_group_id' }, - else: {'@path': '$.properties.user_group_id'} - } - } } }, perform: (request, { settings, payload }) => { const url = `${apiBaseUrl}/applications/${settings.clientId}/segment-audience-sync/` - const { audience_id, audience_name, action, timestamp, livelike_profile_id, user_id, user_group_id, traits_or_properties } = payload + const { audience_id, audience_name, action, timestamp, user_id, traits_or_properties: { livelike_profile_id } = {}, traits_or_properties } = payload; const actionValue = typeof action === 'boolean' ? action : traits_or_properties?.[audience_name] - + delete traits_or_properties[audience_name] + if(livelike_profile_id){ + delete traits_or_properties[livelike_profile_id] + } 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.') } @@ -101,7 +104,7 @@ const action: ActionDefinition = { timestamp, livelike_profile_id, user_id, - user_group_id + traits_or_properties } return request(url, { diff --git a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/types.ts b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/types.ts index 512e581ada9..bedf40677e3 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/types.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/types.ts @@ -8,5 +8,7 @@ export interface UserGroupJSON { // optional fields livelike_profile_id?: string user_id?: string - user_group_id?: string + traits_or_properties?: { + [k: string]: unknown + } } \ No newline at end of file From 3167cc1d968743c48d7281a9bc161e4f7b8f28f0 Mon Sep 17 00:00:00 2001 From: Joe Ayoub Date: Mon, 28 Jul 2025 13:22:50 +0100 Subject: [PATCH 3/5] unit tests done --- .../livelike-cloud/__tests__/index.test.ts | 2 +- .../{properties.ts => constants.ts} | 0 .../src/destinations/livelike-cloud/index.ts | 2 +- .../syncToUserGroup/__tests__/index.test.ts | 391 ++++++++++++++---- .../syncToUserGroup/generated-types.ts | 10 +- .../livelike-cloud/syncToUserGroup/index.ts | 62 ++- .../livelike-cloud/syncToUserGroup/types.ts | 2 +- .../livelike-cloud/syncToUserGroup/utils.ts | 34 ++ .../trackEvent/__tests__/index.test.ts | 2 +- .../livelike-cloud/trackEvent/index.ts | 2 +- 10 files changed, 388 insertions(+), 119 deletions(-) rename packages/destination-actions/src/destinations/livelike-cloud/{properties.ts => constants.ts} (100%) create mode 100644 packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/utils.ts 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/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 b1fdd97c669..43cc8000e4d 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/index.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/index.ts @@ -1,6 +1,6 @@ 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' 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 index 03fdb7e7e27..fe4ab4da118 100644 --- 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 @@ -29,28 +29,30 @@ describe('LivelikeCloud.syncToUserGroup', () => { audience_id: { '@path': '$.context.personas.computation_id'}, audience_name: {'@path': '$.context.personas.computation_key'} , timestamp: { '@path': '$.timestamp' }, - traits_or_properties: { + traits_or_properties_hidden: { '@if': { exists: { '@path': '$.traits' }, then: { '@path': '$.traits' }, else: { '@path': '$.properties' } } }, - livelike_profile_id: { - '@if': { - exists: {'@path': '$.traits.livelike_profile_id'}, - then: {'@path': '$.traits.livelike_profile_id' }, - else: {'@path': '$.properties.livelike_profile_id'} + 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'}, - user_group_id: { - '@if': { - exists: {'@path': '$.traits.user_group_id'}, - then: {'@path': '$.traits.user_group_id' }, - else: {'@path': '$.properties.user_group_id'} - } - } + user_id: { '@path': '$.userId'} } const settings = { @@ -62,11 +64,10 @@ describe('LivelikeCloud.syncToUserGroup', () => { const engageAddAudienceTrack = createTestEvent({ properties: { - audience_key: "test_audience", livelike_profile_id: "122", test_audience: true, - user_group_id: "456", - user_id: "900" + user_id: "900", + email: "test@test.com" }, timestamp: "2025-07-02T16:26:57.511Z", context: { @@ -98,15 +99,15 @@ describe('LivelikeCloud.syncToUserGroup', () => { engageAddAudienceTrack.traits = undefined - const addJson = { + 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', - user_group_id: '456' - } + email: "test@test.com" + }] nock(apiBaseUrl) .post('/applications/test-client-id/segment-audience-sync/', addJson) @@ -122,14 +123,12 @@ describe('LivelikeCloud.syncToUserGroup', () => { expect(responses[0].status).toBe(200) }) - it('should remove user from Audience with an Engage identify() call', async () => { - - const engageRemoveAudienceIdentify = createTestEvent({ - traits: { - audience_key: "test_audience", - livelike_profile_id: "122", + + it('should remove user from Audience with an Engage track() call', async () => { + + const engageAddAudienceTrack = createTestEvent({ + properties: { test_audience: false, - user_group_id: "456", user_id: "900" }, timestamp: "2025-07-02T16:26:57.511Z", @@ -157,95 +156,327 @@ describe('LivelikeCloud.syncToUserGroup', () => { LiveLike: true }, userId: "900", - type: "identify" + type: "track" }) - engageRemoveAudienceIdentify.properties = undefined + engageAddAudienceTrack.traits = undefined - const removeJson = { + 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', - user_group_id: '456' - } + email: "test@test.com" + }] nock(apiBaseUrl) - .post('/applications/test-client-id/segment-audience-sync/', removeJson) + .post('/applications/test-client-id/segment-audience-sync/', addJson) .reply(200); - const responses = await testDestination.testAction('syncToUserGroup', - { - event: engageRemoveAudienceIdentify, - settings, - mapping - } - ) + 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('Non Engage payloads' , () => { - it('should remove user from Audience with a non Engage payload', async () => { - - const settings = { - clientId: 'test-client-id', - producerToken: 'test-producer-token' - } + 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' + } - const nonEngageAddTrack = createTestEvent({ + it('Batch: should add and remove users to Audience with an Engage track() call', async () => { + + const engageAddAudienceTrack1 = createTestEvent({ properties: { - audience_id: "custom_audience_id", - audience_name: "custom_audience_name", - livelike_profile_id: "livelike_profile_id_1", - action: true + 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: "Added To Custom User Group", + event: "Audience Entered", receivedAt: "2025-07-02T16:27:10.584Z", + integrations: { + All: false, + LiveLike: true + }, userId: "900", type: "track" }) - const nonEngageJson = { - audience_id: 'custom_audience_id', - audience_name: 'custom_audience_name', + 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: 'livelike_profile_id_1', - user_id: '900' - } - - const nonEngageMapping = { - audience_id: { '@path': '$.properties.audience_id'}, - audience_name: {'@path': '$.properties.audience_name'} , - action: { '@path': '$.properties.action' }, - timestamp: { '@path': '$.timestamp' }, - traits_or_properties: { '@path': '$.properties' }, - livelike_profile_id: {'@path': '$.properties.livelike_profile_id'}, - user_id: { '@path': '$.userId'}, - user_group_id: {'@path': '$.properties.user_group_id'} - } + 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/', nonEngageJson) + .post('/applications/test-client-id/segment-audience-sync/', batchJSON) .reply(200); - const responses = await testDestination.testAction('syncToUserGroup', - { - event: nonEngageAddTrack, - settings, - mapping: nonEngageMapping - } - ) + const responses = await testDestination.testBatchAction('syncToUserGroup', { + events: [engageAddAudienceTrack1, engageAddAudienceTrack2], + settings, + mapping + }) - expect(responses.length).toBe(1) - expect(responses[0].status).toBe(200) + 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 index 9a849615068..1237d39189e 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/generated-types.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/generated-types.ts @@ -18,9 +18,9 @@ export interface Payload { */ timestamp: string /** - * Hidden fields used to figure out if user is added or removed from an Engage Audience + * Used for trait values to send to Livelike. */ - traits_or_properties: { + additional_user_traits?: { /** * The unique LiveLike user identifier. */ @@ -31,6 +31,12 @@ export interface Payload { 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. */ diff --git a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts index 5bc0469e5aa..f4e8941c146 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts @@ -1,8 +1,7 @@ -import { ActionDefinition, PayloadValidationError } from '@segment/actions-core' +import { ActionDefinition } from '@segment/actions-core' import type { Settings } from '../generated-types' import type { Payload } from './generated-types' -import { apiBaseUrl } from '../properties' -import { UserGroupJSON } from './types' +import { processPayloads } from './utils' const action: ActionDefinition = { title: 'Sync to User Group', @@ -39,14 +38,13 @@ const action: ActionDefinition = { required: true, default: { '@path': '$.timestamp' } }, - traits_or_properties: { - label: 'Traits or Properties', - description: 'Hidden fields used to figure out if user is added or removed from an Engage Audience', + additional_user_traits: { + label: 'Additional user traits', + description: 'Used for trait values to send to Livelike.', type: 'object', unsafe_hidden: true, - defaultObjectUI: 'keyvalue', + defaultObjectUI: 'keyvalue:only', additionalProperties: true, - required: true, properties: { livelike_profile_id: { label: 'LiveLike User Profile ID', @@ -76,6 +74,18 @@ const action: ActionDefinition = { } } }, + 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', @@ -83,34 +93,22 @@ const action: ActionDefinition = { 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: 1000 } }, perform: (request, { settings, payload }) => { - const url = `${apiBaseUrl}/applications/${settings.clientId}/segment-audience-sync/` - const { audience_id, audience_name, action, timestamp, user_id, traits_or_properties: { livelike_profile_id } = {}, traits_or_properties } = payload; - const actionValue = typeof action === 'boolean' ? action : traits_or_properties?.[audience_name] - delete traits_or_properties[audience_name] - if(livelike_profile_id){ - delete traits_or_properties[livelike_profile_id] - } - 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.') - } + return processPayloads(request, [payload], settings) - const json: UserGroupJSON = { - audience_id, - audience_name, - action: actionValue, - timestamp, - livelike_profile_id, - user_id, - traits_or_properties - } - - return request(url, { - method: 'post', - json - }) + }, + performBatch: (request, { settings, payload }) => { + return processPayloads(request, payload, settings) } } diff --git a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/types.ts b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/types.ts index bedf40677e3..556d1741dca 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/types.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/types.ts @@ -1,4 +1,4 @@ -export interface UserGroupJSON { +export interface UserGroupItem { // required fields audience_id: string audience_name: string 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[]) => { From e8bf94c5a160e4fb75ef0f352c013601b99dcfa2 Mon Sep 17 00:00:00 2001 From: Joe Ayoub Date: Tue, 29 Jul 2025 13:28:18 +0100 Subject: [PATCH 4/5] specifying batch size --- .../livelike-cloud/syncToUserGroup/generated-types.ts | 4 ++++ 1 file changed, 4 insertions(+) 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 index 1237d39189e..dc6bddc67e9 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/generated-types.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/generated-types.ts @@ -41,4 +41,8 @@ export interface Payload { * A unique identifier for a user. */ user_id?: string + /** + * The number of records to process in each batch. Default is 100. + */ + batch_size?: number } From 6e231022eafc25fe0a324cce809f953ae9f6a85b Mon Sep 17 00:00:00 2001 From: Joe Ayoub Date: Tue, 29 Jul 2025 14:40:02 +0100 Subject: [PATCH 5/5] changing max batch size --- .../livelike-cloud/syncToUserGroup/index.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts index f4e8941c146..6ef362b4c01 100644 --- a/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts +++ b/packages/destination-actions/src/destinations/livelike-cloud/syncToUserGroup/index.ts @@ -5,7 +5,8 @@ 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.', + 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: { @@ -24,12 +25,13 @@ const action: ActionDefinition = { 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.' + 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', @@ -100,12 +102,11 @@ const action: ActionDefinition = { description: 'The number of records to process in each batch. Default is 100.', default: 100, minimum: 1, - maximum: 1000 + maximum: 500 } }, perform: (request, { settings, payload }) => { return processPayloads(request, [payload], settings) - }, performBatch: (request, { settings, payload }) => { return processPayloads(request, payload, settings)