diff --git a/packages/destination-actions/src/destinations/memora-internal/__tests__/index.test.ts b/packages/destination-actions/src/destinations/memora-internal/__tests__/index.test.ts new file mode 100644 index 00000000000..e70d756c833 --- /dev/null +++ b/packages/destination-actions/src/destinations/memora-internal/__tests__/index.test.ts @@ -0,0 +1,68 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../index' +import { API_VERSION } from '../../memora/versioning-info' +import { BASE_URL } from '../../memora/constants' + +const testDestination = createTestIntegration(Destination) + +const defaultSettings = { + username: 'test-api-key', + password: 'test-api-secret', + twilioAccount: 'AC1234567890' +} + +const defaultMapping = { + memora_store: 'test-store-id', + profile_identifiers: { + 'Contact.$.email': { '@path': '$.traits.email' }, + 'Contact.$.phone': { '@path': '$.traits.phone' } + }, + profile_traits: { + 'Contact.$.firstName': { '@path': '$.traits.first_name' } + } +} + +describe('Memora Internal (actions-memora-internal)', () => { + beforeEach(() => { + nock.cleanAll() + }) + + it('should not include segment_traits_by_field or segment_identifiers_by_field in the outbound request', async () => { + const event = createTestEvent({ + type: 'identify', + userId: 'user-123', + traits: { email: 'john@example.com', phone: '+1-555-0100', first_name: 'John' } + }) + + let capturedBody: Record = {} + let nockIntercepted = false + + nock(BASE_URL) + .put(`/${API_VERSION}/Stores/test-store-id/Profiles/Bulk`, (body) => { + capturedBody = body as Record + nockIntercepted = true + return true + }) + .reply(202) + + const responses = await testDestination.testAction('upsertProfile', { + event, + settings: defaultSettings, + mapping: { + ...defaultMapping, + segment_traits_by_field: { 'Contact.$.firstName': ['first_name'] }, + segment_identifiers_by_field: { 'Contact.$.email': ['email'] } + }, + useDefaultMappings: true + }) + + expect(nockIntercepted).toBe(true) + expect(responses.length).toBe(1) + expect(responses[0].status).toBe(202) + + const requestBodyStr = JSON.stringify(capturedBody) + expect(requestBodyStr).not.toContain('segment_traits_by_field') + expect(requestBodyStr).not.toContain('segment_identifiers_by_field') + }) +}) diff --git a/packages/destination-actions/src/destinations/memora-internal/index.ts b/packages/destination-actions/src/destinations/memora-internal/index.ts index e8aa734b498..e9b5a4fe5a4 100644 --- a/packages/destination-actions/src/destinations/memora-internal/index.ts +++ b/packages/destination-actions/src/destinations/memora-internal/index.ts @@ -5,7 +5,47 @@ import memoraDestination from '../memora' const destination: DestinationDefinition = { ...memoraDestination, name: 'Memora Internal', - slug: 'actions-memora-internal' + slug: 'actions-memora-internal', + actions: { + upsertProfile: { + ...memoraDestination.actions.upsertProfile, + fields: { + ...memoraDestination.actions.upsertProfile.fields, + /** + * Used by the Segment control plane as part of the Conversation Memory Sync feature. + * The control plane writes this map when creating or updating a mapping, and reads it back + * to build the event-emitter enrichment mapping that ensures the referenced Segment traits + * are present in event payloads at runtime. Not consumed by this action itself — marked + * unsafe_hidden so it round-trips through subscription settings without being exposed or stripped. + */ + segment_traits_by_field: { + label: 'Segment Traits Used', + description: + 'Per-field map of Segment trait names referenced by each directive (keyed by stored field key). Used by the control plane to wire up event-emitter enrichment. Set automatically — do not edit manually.', + type: 'object' as const, + required: false, + additionalProperties: true, + unsafe_hidden: true + }, + /** + * Used by the Segment control plane as part of the Conversation Memory Sync feature. + * The control plane writes this map when creating or updating a mapping, and reads it back + * to populate id_sync so that the declared Segment identifiers are available as external IDs + * at runtime. Not consumed by this action itself — marked unsafe_hidden so it round-trips + * through subscription settings without being exposed or stripped. + */ + segment_identifiers_by_field: { + label: 'Segment Identifiers Used', + description: + 'Per-field map of Segment identifier names referenced by each directive (keyed by stored field key). Used by the control plane to wire up id_sync. Set automatically — do not edit manually.', + type: 'object' as const, + required: false, + additionalProperties: true, + unsafe_hidden: true + } + } + } + } } export default destination diff --git a/packages/destination-actions/src/destinations/memora-internal/upsertProfile.types.ts b/packages/destination-actions/src/destinations/memora-internal/upsertProfile.types.ts index 0fcaadddded..a17761c640d 100644 --- a/packages/destination-actions/src/destinations/memora-internal/upsertProfile.types.ts +++ b/packages/destination-actions/src/destinations/memora-internal/upsertProfile.types.ts @@ -25,4 +25,16 @@ export interface Payload { profile_traits?: { [k: string]: unknown } + /** + * Per-field map of Segment trait names referenced by each directive (keyed by stored field key). Used by the control plane to wire up event-emitter enrichment. Set automatically — do not edit manually. + */ + segment_traits_by_field?: { + [k: string]: unknown + } + /** + * Per-field map of Segment identifier names referenced by each directive (keyed by stored field key). Used by the control plane to wire up id_sync. Set automatically — do not edit manually. + */ + segment_identifiers_by_field?: { + [k: string]: unknown + } }