diff --git a/CHANGELOG.md b/CHANGELOG.md index d3f2b57d19..5d3a37e122 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.60.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.57.1...v1.60.0) (2024-03-20) + + +### Features + +* ninetailed: add default value for context.location as {} ([#3197](https://github.com/rudderlabs/rudder-transformer/issues/3197)) ([91fc0fb](https://github.com/rudderlabs/rudder-transformer/commit/91fc0fb3e9eeb127298a0ce305ef6d1d7b72a39f)) + + +### Bug Fixes + +* heap: make userId as required for track and identify call ([#3198](https://github.com/rudderlabs/rudder-transformer/issues/3198)) ([6a7c534](https://github.com/rudderlabs/rudder-transformer/commit/6a7c534a7df812bb7e39c1905eadcc29d7cd1329)) +* tiktok_ads: validate message.event type ([#3203](https://github.com/rudderlabs/rudder-transformer/issues/3203)) ([a86c277](https://github.com/rudderlabs/rudder-transformer/commit/a86c2771034877cef4161cda61bcda5fdda2d89f)) + ## [1.59.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.57.1...v1.59.0) (2024-03-18) diff --git a/package-lock.json b/package-lock.json index 63f19b12c3..5701e64a62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rudder-transformer", - "version": "1.59.0", + "version": "1.60.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rudder-transformer", - "version": "1.59.0", + "version": "1.60.0", "license": "ISC", "dependencies": { "@amplitude/ua-parser-js": "0.7.24", diff --git a/package.json b/package.json index 51b8b43a54..5c1d9c1848 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rudder-transformer", - "version": "1.59.0", + "version": "1.60.0", "description": "", "homepage": "https://github.com/rudderlabs/rudder-transformer#readme", "bugs": { diff --git a/src/cdk/v2/destinations/heap/procWorkflow.yaml b/src/cdk/v2/destinations/heap/procWorkflow.yaml index 8326a61a79..ac12e7e02a 100644 --- a/src/cdk/v2/destinations/heap/procWorkflow.yaml +++ b/src/cdk/v2/destinations/heap/procWorkflow.yaml @@ -40,7 +40,9 @@ steps: }); .message.properties.idempotencyKey ? ($.context.payload.idempotency_key = .message.properties.idempotencyKey); - + - name: validateuserId + template: | + $.assert($.context.payload.identity, "userId is required"); - name: finalPayload description: In batchMode we return payload directly condition: $.batchMode diff --git a/src/cdk/v2/destinations/ninetailed/data/contextMapping.json b/src/cdk/v2/destinations/ninetailed/data/contextMapping.json index 3d6392dd1e..f2373b61c1 100644 --- a/src/cdk/v2/destinations/ninetailed/data/contextMapping.json +++ b/src/cdk/v2/destinations/ninetailed/data/contextMapping.json @@ -37,7 +37,10 @@ }, { "sourceKeys": "location", - "required": true, + "required": false, + "metadata": { + "defaultValue": {} + }, "destKey": "location" } ] diff --git a/src/features.json b/src/features.json index 76b562a825..267923fdb4 100644 --- a/src/features.json +++ b/src/features.json @@ -85,5 +85,5 @@ "SPRIG" ], "supportSourceTransformV1": true, - "supportTransformerProxyV1": false + "supportTransformerProxyV1": true } diff --git a/src/v0/destinations/tiktok_ads/transform.js b/src/v0/destinations/tiktok_ads/transform.js index ba852b9a97..17a37984c3 100644 --- a/src/v0/destinations/tiktok_ads/transform.js +++ b/src/v0/destinations/tiktok_ads/transform.js @@ -19,6 +19,7 @@ const { getHashFromArrayWithDuplicate, handleRtTfSingleEventError, batchMultiplexedEvents, + validateEventName, } = require('../../util'); const { process: processV2, processRouterDest: processRouterDestV2 } = require('./transformV2'); const { getContents } = require('./util'); @@ -129,12 +130,9 @@ const getTrackResponse = (message, Config, event) => { const trackResponseBuilder = async (message, { Config }) => { const { eventsToStandard, sendCustomEvents } = Config; - if (!message.event || typeof message.event !== 'string') { - throw new InstrumentationError('Either event name is not present or it is not a string'); - } - let event = message.event?.toLowerCase().trim(); + validateEventName(message.event); + let event = message.event.toLowerCase().trim(); const standardEventsMap = getHashFromArrayWithDuplicate(eventsToStandard); - if (!sendCustomEvents && eventNameMapping[event] === undefined && !standardEventsMap[event]) { throw new InstrumentationError( `Event name (${event}) is not valid, must be mapped to one of standard events`, diff --git a/src/v0/destinations/tiktok_ads/transformV2.js b/src/v0/destinations/tiktok_ads/transformV2.js index 48c5b19e64..3bd8699e3a 100644 --- a/src/v0/destinations/tiktok_ads/transformV2.js +++ b/src/v0/destinations/tiktok_ads/transformV2.js @@ -14,6 +14,7 @@ const { getDestinationExternalID, getHashFromArrayWithDuplicate, handleRtTfSingleEventError, + validateEventName, } = require('../../util'); const { getContents, hashUserField } = require('./util'); const config = require('./config'); @@ -59,7 +60,7 @@ const getTrackResponsePayload = (message, destConfig, event) => { const trackResponseBuilder = async (message, { Config }) => { const { eventsToStandard, sendCustomEvents, accessToken, pixelCode } = Config; - + validateEventName(message.event); let event = message.event?.toLowerCase().trim(); if (!event) { throw new InstrumentationError('Event name is required'); diff --git a/test/integrations/destinations/heap/processor/data.ts b/test/integrations/destinations/heap/processor/data.ts index 6efa45435c..f503134148 100644 --- a/test/integrations/destinations/heap/processor/data.ts +++ b/test/integrations/destinations/heap/processor/data.ts @@ -961,4 +961,105 @@ export const data = [ }, }, }, + { + name: 'heap', + description: 'Test 8 -> Identify: No userId is present', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination: { + Config: { + appId: '', + }, + DestinationDefinition: { + Config: { + cdkV2Enabled: true, + }, + DisplayName: 'Heap.io', + ID: '1WTbl0l5GjOQKOvfmcGwk0T49kV', + Name: 'HEAP', + }, + Enabled: true, + ID: '1WTcDSEOE437e4ePH10BJNELXmE', + Name: 'heap test', + Transformations: [], + }, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + message: { + channel: 'web', + context: { + app: { + build: '1.0.0', + name: 'RudderLabs JavaScript SDK', + namespace: 'com.rudderlabs.javascript', + version: '1.0.0', + }, + ip: '0.0.0.0', + library: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + locale: 'en-US', + os: { + name: '', + version: '', + }, + screen: { + density: 2, + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', + }, + integrations: { + All: true, + }, + traits: { + email: 'sampath@gmail.com', + }, + messageId: 'fca2e71a-5d30-48e1-ba45-761c16e3820f', + originalTimestamp: '2020-01-16T13:21:59.076Z', + receivedAt: '2020-01-16T18:52:03.871+05:30', + request_ip: '[::1]:62312', + sentAt: '2020-01-16T13:22:03.85Z', + timestamp: '2020-01-16T18:51:59.097+05:30', + type: 'identify', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: + 'userId is required: Workflow: procWorkflow, Step: validateuserId, ChildStep: undefined, OriginalError: userId is required', + statTags: { + destinationId: 'destId', + workspaceId: 'wspId', + destType: 'HEAP', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'cdkV2', + module: 'destination', + }, + statusCode: 400, + metadata: { + destinationId: 'destId', + workspaceId: 'wspId', + }, + }, + ], + }, + }, + }, ]; diff --git a/test/integrations/destinations/ninetailed/commonConfig.ts b/test/integrations/destinations/ninetailed/commonConfig.ts index 3b5d4149f2..4baf72dee1 100644 --- a/test/integrations/destinations/ninetailed/commonConfig.ts +++ b/test/integrations/destinations/ninetailed/commonConfig.ts @@ -71,7 +71,41 @@ export const context = { timezone: 'America/Los_Angeles', }, }; - +export const contextWithNoLocation = { + app: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + campaign: { + name: 'campign_123', + source: 'social marketing', + medium: 'facebook', + term: '1 year', + }, + library: { + name: 'RudderstackSDK', + version: 'Ruddderstack SDK version', + }, + locale: 'en-US', + page: { + path: '/signup', + referrer: 'https://rudderstack.medium.com/', + search: '?type=freetrial', + url: 'https://app.rudderstack.com/signup?type=freetrial', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', +}; +export const commonInputWithNoLocation = { + anonymousId: 'anon_123', + messageId: 'dummy_msg_id', + context: contextWithNoLocation, + channel: 'web', + integrations: { + All: true, + }, + originalTimestamp: '2021-01-25T15:32:56.409Z', +}; export const commonInput = { anonymousId: 'anon_123', messageId: 'dummy_msg_id', diff --git a/test/integrations/destinations/ninetailed/processor/identify.ts b/test/integrations/destinations/ninetailed/processor/identify.ts index fbd7379e19..3bb333c160 100644 --- a/test/integrations/destinations/ninetailed/processor/identify.ts +++ b/test/integrations/destinations/ninetailed/processor/identify.ts @@ -2,6 +2,7 @@ import { destination, traits, commonInput, + commonInputWithNoLocation, metadata, processInstrumentationErrorStatTags, } from '../commonConfig'; @@ -152,4 +153,92 @@ export const identify = [ }, }, }, + { + id: 'ninetailed-test-identify-success-3', + name: 'ninetailed', + description: 'identify call with no context.location present and {} is used as default', + scenario: 'Framework+Buisness', + successCriteria: 'Response should contain context.location as {} and status code should be 200', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: { + type: 'identify', + ...commonInputWithNoLocation, + userId: 'sajal12', + traits: traits, + integrations: { + All: true, + }, + originalTimestamp: '2021-01-25T15:32:56.409Z', + }, + metadata, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + metadata: { + destinationId: 'dummyDestId', + }, + output: transformResultBuilder({ + method: 'POST', + endpoint: + 'https://experience.ninetailed.co/v2/organizations/dummyOrganisationId/environments/main/events', + JSON: { + events: [ + { + context: { + app: { + name: 'RudderLabs JavaScript SDK', + version: '1.0.0', + }, + campaign: { + name: 'campign_123', + source: 'social marketing', + medium: 'facebook', + term: '1 year', + }, + library: { + name: 'RudderstackSDK', + version: 'Ruddderstack SDK version', + }, + locale: 'en-US', + page: { + path: '/signup', + referrer: 'https://rudderstack.medium.com/', + search: '?type=freetrial', + url: 'https://app.rudderstack.com/signup?type=freetrial', + }, + userAgent: + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36', + location: {}, + }, + type: 'identify', + channel: 'web', + userId: 'sajal12', + messageId: 'dummy_msg_id', + traits: traits, + anonymousId: 'anon_123', + originalTimestamp: '2021-01-25T15:32:56.409Z', + }, + ], + }, + userId: '', + }), + statusCode: 200, + }, + ], + }, + }, + }, ]; diff --git a/test/integrations/destinations/tiktok_ads/processor/data.ts b/test/integrations/destinations/tiktok_ads/processor/data.ts index d0447da43c..429024b8a9 100644 --- a/test/integrations/destinations/tiktok_ads/processor/data.ts +++ b/test/integrations/destinations/tiktok_ads/processor/data.ts @@ -1369,7 +1369,7 @@ export const data = [ body: [ { statusCode: 400, - error: 'Either event name is not present or it is not a string', + error: 'Event is a required field and should be a string', statTags: { errorCategory: 'dataValidation', errorType: 'instrumentation', @@ -6055,7 +6055,7 @@ export const data = [ body: [ { statusCode: 400, - error: 'Event name is required', + error: 'Event is a required field and should be a string', statTags: { errorCategory: 'dataValidation', errorType: 'instrumentation', @@ -7004,7 +7004,7 @@ export const data = [ body: [ { statusCode: 400, - error: 'Either event name is not present or it is not a string', + error: 'Event is a required field and should be a string', statTags: { errorCategory: 'dataValidation', errorType: 'instrumentation',