diff --git a/.github/workflows/create-hotfix-branch.yml b/.github/workflows/create-hotfix-branch.yml
index d1397cb608..97611f1eee 100644
--- a/.github/workflows/create-hotfix-branch.yml
+++ b/.github/workflows/create-hotfix-branch.yml
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
# Only allow these users to create new hotfix branch from 'main'
- if: github.ref == 'refs/heads/main' && (github.actor == 'ItsSudip' || github.actor == 'krishna2020' || github.actor == 'saikumarrs' || github.actor == 'sandeepdsvs' || github.actor == 'shrouti1507' || github.actor == 'anantjain45823' || github.actor == 'chandumlg' || github.actor == 'mihir-4116') && (github.triggering_actor == 'ItsSudip' || github.triggering_actor == 'krishna2020' || github.triggering_actor == 'saikumarrs' || github.triggering_actor == 'sandeepdsvs' || github.triggering_actor == 'shrouti1507' || github.triggering_actor == 'anantjain45823' || github.triggering_actor == 'chandumlg' || github.triggering_actor == 'mihir-4116')
+ if: github.ref == 'refs/heads/main' && (github.actor == 'ItsSudip' || github.actor == 'krishna2020' || github.actor == 'saikumarrs' || github.actor == 'sandeepdsvs' || github.actor == 'shrouti1507' || github.actor == 'anantjain45823' || github.actor == 'chandumlg' || github.actor == 'mihir-4116' || github.actor == 'ujjwal-ab') && (github.triggering_actor == 'ItsSudip' || github.triggering_actor == 'krishna2020' || github.triggering_actor == 'saikumarrs' || github.triggering_actor == 'sandeepdsvs' || github.triggering_actor == 'shrouti1507' || github.triggering_actor == 'anantjain45823' || github.triggering_actor == 'chandumlg' || github.triggering_actor == 'mihir-4116' || github.triggering_actor == 'ujjwal-ab)
steps:
- name: Create Branch
uses: peterjgrainger/action-create-branch@v2.4.0
diff --git a/.github/workflows/draft-new-release.yml b/.github/workflows/draft-new-release.yml
index a0a558440a..23e243918f 100644
--- a/.github/workflows/draft-new-release.yml
+++ b/.github/workflows/draft-new-release.yml
@@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
# Only allow release stakeholders to initiate releases
- if: (github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/heads/hotfix/')) && (github.actor == 'ItsSudip' || github.actor == 'krishna2020' || github.actor == 'saikumarrs' || github.actor == 'sandeepdsvs' || github.actor == 'shrouti1507' || github.actor == 'anantjain45823' || github.actor == 'chandumlg' || github.actor == 'mihir-4116' || github.actor == 'yashasvibajpai' || github.actor == 'sanpj2292') && (github.triggering_actor == 'ItsSudip' || github.triggering_actor == 'krishna2020' || github.triggering_actor == 'saikumarrs' || github.triggering_actor == 'sandeepdsvs' || github.triggering_actor == 'shrouti1507' || github.triggering_actor == 'anantjain45823' || github.triggering_actor == 'chandumlg' || github.triggering_actor == 'mihir-4116' || github.triggering_actor == 'yashasvibajpai' || github.triggering_actor == 'sanpj2292')
+ if: (github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/heads/hotfix/')) && (github.actor == 'ItsSudip' || github.actor == 'krishna2020' || github.actor == 'saikumarrs' || github.actor == 'sandeepdsvs' || github.actor == 'shrouti1507' || github.actor == 'anantjain45823' || github.actor == 'chandumlg' || github.actor == 'mihir-4116' || github.actor == 'yashasvibajpai' || github.actor == 'sanpj2292' || github.actor == 'ujjwal-ab') && (github.triggering_actor == 'ItsSudip' || github.triggering_actor == 'krishna2020' || github.triggering_actor == 'saikumarrs' || github.triggering_actor == 'sandeepdsvs' || github.triggering_actor == 'shrouti1507' || github.triggering_actor == 'anantjain45823' || github.triggering_actor == 'chandumlg' || github.triggering_actor == 'mihir-4116' || github.triggering_actor == 'yashasvibajpai' || github.triggering_actor == 'sanpj2292' || github.triggering_actor == 'ujjwal-ab')
steps:
- name: Checkout
uses: actions/checkout@v3.5.3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 01631435d2..b9256fa915 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,22 @@
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.49.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.48.0...v1.49.0) (2023-11-06)
+
+
+### Features
+
+* add new destination tiktok_audience ([#2710](https://github.com/rudderlabs/rudder-transformer/issues/2710)) ([9bc0fd8](https://github.com/rudderlabs/rudder-transformer/commit/9bc0fd8efcee44871a190bd6cb9e89c5cf035ff8))
+* onboard one signal to router transform ([#2785](https://github.com/rudderlabs/rudder-transformer/issues/2785)) ([818858e](https://github.com/rudderlabs/rudder-transformer/commit/818858e046ce5f9735bbb97715c43a959ad3aa3c))
+* onboard revenuecat as a source ([#2774](https://github.com/rudderlabs/rudder-transformer/issues/2774)) ([55f9637](https://github.com/rudderlabs/rudder-transformer/commit/55f96374b4d73db7013c1d5e72bfc9c8257b224b))
+
+
+### Bug Fixes
+
+* add check to remove null and undefined properties before sending ([#2796](https://github.com/rudderlabs/rudder-transformer/issues/2796)) ([6e89cd3](https://github.com/rudderlabs/rudder-transformer/commit/6e89cd3f67ea887ba17c1cd5ffbca6675f54d96c))
+* allow support for full url from UI in freshsales and freshmarketer ([#2780](https://github.com/rudderlabs/rudder-transformer/issues/2780)) ([570532c](https://github.com/rudderlabs/rudder-transformer/commit/570532ce790c05a69621d9289758a1b1a7acda8c))
+* busgnag issues for klaviyo, freshsales, customeio ([#2795](https://github.com/rudderlabs/rudder-transformer/issues/2795)) ([11fb7c4](https://github.com/rudderlabs/rudder-transformer/commit/11fb7c47910681833e37d25a1573d2005e62742b))
+
## [1.48.0](https://github.com/rudderlabs/rudder-transformer/compare/v1.47.0...v1.48.0) (2023-11-02)
diff --git a/package-lock.json b/package-lock.json
index 0822a9b42b..5e857f6bb9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "rudder-transformer",
- "version": "1.48.0",
+ "version": "1.49.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "rudder-transformer",
- "version": "1.48.0",
+ "version": "1.49.0",
"license": "ISC",
"dependencies": {
"@amplitude/ua-parser-js": "^0.7.24",
diff --git a/package.json b/package.json
index 46f728664d..ac0ae2bbeb 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "rudder-transformer",
- "version": "1.48.0",
+ "version": "1.49.0",
"description": "",
"homepage": "https://github.com/rudderlabs/rudder-transformer#readme",
"bugs": {
diff --git a/src/cdk/v2/bindings/default.js b/src/cdk/v2/bindings/default.js
index 0bba7210f0..b86b6d2b63 100644
--- a/src/cdk/v2/bindings/default.js
+++ b/src/cdk/v2/bindings/default.js
@@ -1,3 +1,4 @@
+const crypto = require('crypto');
const {
InstrumentationError,
ConfigurationError,
@@ -47,7 +48,12 @@ function assertHttpResp(processedResponse, message) {
}
}
+function MD5(data) {
+ return crypto.createHash('md5').update(data).digest('hex');
+}
+
module.exports = {
+ MD5,
isValidEventType,
assert,
assertConfig,
diff --git a/src/cdk/v2/destinations/tiktok_audience/config.js b/src/cdk/v2/destinations/tiktok_audience/config.js
new file mode 100644
index 0000000000..853f372505
--- /dev/null
+++ b/src/cdk/v2/destinations/tiktok_audience/config.js
@@ -0,0 +1,9 @@
+const ACTION_MAP = {
+ add: 'add',
+ remove: 'delete',
+};
+const SHA256_TRAITS = ['IDFA_SHA256', 'AAID_SHA256', 'EMAIL_SHA256', 'PHONE_SHA256'];
+module.exports = {
+ ACTION_MAP,
+ SHA256_TRAITS,
+};
diff --git a/src/cdk/v2/destinations/tiktok_audience/procWorkflow.yaml b/src/cdk/v2/destinations/tiktok_audience/procWorkflow.yaml
new file mode 100644
index 0000000000..cd84ecbc87
--- /dev/null
+++ b/src/cdk/v2/destinations/tiktok_audience/procWorkflow.yaml
@@ -0,0 +1,67 @@
+
+bindings:
+ - name: EventType
+ path: ../../../../constants
+ - path: ../../bindings/jsontemplate
+ exportAll: true
+ - path: ./config
+ - name: removeUndefinedAndNullValues
+ path: ../../../../v0/util
+ - name: defaultRequestConfig
+ path: ../../../../v0/util
+
+steps:
+ - name: validateInput
+ template: |
+ let messageType = .message.type;
+ $.assert(.message.type, "message Type is not present. Aborting message.");
+ $.assert(.message.type.toLowerCase() ==='audiencelist', "Event type " + .message.type.toLowerCase() + " is not supported. Aborting message.");
+ $.assert(.message.properties, "Message properties is not present. Aborting message.");
+ $.assert(.message.properties.listData, "listData is not present inside properties. Aborting message.");
+ $.assert($.containsAll(Object.keys(.message.properties.listData), ["add", "remove"]), "unsupported action type. Aborting message.")
+
+ - name: prepareIdentifiersList
+ description: |
+ Populate list of identifiers to be updated
+ template: |
+ const destinationFields = .message.context.destinationFields.split(", ")
+ const audienceId = .message.context.externalId[0].type.split("-")[1];
+ const isHashRequired = .destination.Config.isHashRequired;
+ const advertiserIds = .metadata.secret.advertiserIds;
+ const hashTraits = function(traits) {
+ traits@trait.(destinationFields@destinationField.(
+ trait[destinationField] ? {
+ id: isHashRequired ?
+ destinationField in $.SHA256_TRAITS ?
+ $.SHA256(trait[destinationField]) : $.MD5(trait[destinationField])
+ : trait[destinationField],
+ audience_ids:[audienceId]
+ } : {}
+ )[])
+ };
+ const listData = .message.properties.listData;
+ const actions = Object.keys(listData)
+ actions@action.({
+ "batch_data": hashTraits(listData[action]),
+ "id_schema": destinationFields,
+ "advertiser_ids": advertiserIds,
+ "action": $.ACTION_MAP[action],
+ })[]
+
+
+ - name: buildResponseForProcessTransformation
+ description: build response
+ template: |
+ const accessToken = .metadata.secret.accessToken
+ const anonymousId = .message.anonymousId;
+ $.outputs.prepareIdentifiersList@body.(
+ let response = $.defaultRequestConfig();
+ response.body.JSON = body;
+ response.userId = anonymousId;
+ response.endpoint = "https://business-api.tiktok.com/open_api/v1.3/segment/mapping/";
+ response.headers = {
+ "Access-Token": accessToken,
+ "Content-Type": "application/json"
+ };
+ response
+ )
diff --git a/src/cdk/v2/destinations/tiktok_audience/rtWorkflow.yaml b/src/cdk/v2/destinations/tiktok_audience/rtWorkflow.yaml
new file mode 100644
index 0000000000..3db4c405ad
--- /dev/null
+++ b/src/cdk/v2/destinations/tiktok_audience/rtWorkflow.yaml
@@ -0,0 +1,32 @@
+bindings:
+ - name: handleRtTfSingleEventError
+ path: ../../../../v0/util/index
+
+steps:
+ - name: validateInput
+ template: |
+ $.assert(Array.isArray(^) && ^.length > 0, "Invalid event array")
+
+ - name: transform
+ externalWorkflow:
+ path: ./procWorkflow.yaml
+ loopOverInput: true
+
+ - name: successfulEvents
+ debug: true
+ template: |
+ $.outputs.transform#idx{"output" in .}.({
+ "batchedRequest": .output,
+ "batched": true,
+ "destination": ^[idx].destination,
+ "metadata": ^[idx].metadata[],
+ "statusCode": 200
+ })[]
+ - name: failedEvents
+ template: |
+ $.outputs.transform#idx.error.(
+ $.handleRtTfSingleEventError(^[idx], .originalError ?? ., {})
+ )[]
+ - name: finalPayload
+ template: |
+ [...$.outputs.failedEvents, ...$.outputs.successfulEvents]
diff --git a/src/features.json b/src/features.json
index 7de214ab39..9793f667e3 100644
--- a/src/features.json
+++ b/src/features.json
@@ -58,6 +58,8 @@
"OPTIMIZELY_FULLSTACK": true,
"TWITTER_ADS": true,
"CLEVERTAP": true,
- "ORTTO": true
+ "ORTTO": true,
+ "ONE_SIGNAL": true,
+ "TIKTOK_AUDIENCE": true
}
}
diff --git a/src/v0/destinations/adobe_analytics/transform.js b/src/v0/destinations/adobe_analytics/transform.js
index 54806bf578..67bb66310a 100644
--- a/src/v0/destinations/adobe_analytics/transform.js
+++ b/src/v0/destinations/adobe_analytics/transform.js
@@ -11,6 +11,7 @@ const {
isDefinedAndNotNull,
isDefinedAndNotNullAndNotEmpty,
getIntegrationsObj,
+ removeUndefinedAndNullValues,
simpleProcessRouterDest,
} = require('../../util');
const {
@@ -394,7 +395,7 @@ const handleTrack = (message, destinationConfig) => {
break;
}
- return payload;
+ return removeUndefinedAndNullValues(payload);
};
const process = async (event) => {
diff --git a/src/v0/destinations/am/config.js b/src/v0/destinations/am/config.js
index 5e6fc06c27..3e51a67137 100644
--- a/src/v0/destinations/am/config.js
+++ b/src/v0/destinations/am/config.js
@@ -122,7 +122,8 @@ events.forEach((event) => {
const DELETE_MAX_BATCH_SIZE = 100;
const DESTINATION = 'amplitude';
const IDENTIFY_AM = '$identify';
-
+const AMBatchSizeLimit = 20 * 1024 * 1024; // 20 MB
+const AMBatchEventLimit = 500; // event size limit from sdk is 32KB => 15MB
module.exports = {
DESTINATION,
Event,
@@ -134,4 +135,6 @@ module.exports = {
DELETE_MAX_BATCH_SIZE,
batchEventsWithUserIdLengthLowerThanFive,
IDENTIFY_AM,
+ AMBatchSizeLimit,
+ AMBatchEventLimit
};
diff --git a/src/v0/destinations/am/transform.js b/src/v0/destinations/am/transform.js
index e6ccf585df..04a1c5a107 100644
--- a/src/v0/destinations/am/transform.js
+++ b/src/v0/destinations/am/transform.js
@@ -1,6 +1,7 @@
/* eslint-disable no-lonely-if */
/* eslint-disable no-nested-ternary */
/* eslint-disable no-param-reassign */
+const cloneDeep = require('lodash/cloneDeep');
const get = require('get-value');
const set = require('set-value');
const {
@@ -26,6 +27,7 @@ const {
isAppleFamily,
isDefinedAndNotNullAndNotEmpty,
simpleProcessRouterDest,
+ isValidInteger,
} = require('../../util');
const {
BASE_URL,
@@ -34,18 +36,17 @@ const {
mappingConfig,
batchEventsWithUserIdLengthLowerThanFive,
IDENTIFY_AM,
+ AMBatchSizeLimit,
+ AMBatchEventLimit,
} = require('./config');
const tags = require('../../util/tags');
const AMUtils = require('./utils');
const logger = require('../../../logger');
-const { InstrumentationError } = require('../../util/errorTypes');
+const { InstrumentationError, ConfigurationError } = require('../../util/errorTypes');
const { JSON_MIME_TYPE } = require('../../util/constant');
-const AMBatchSizeLimit = 20 * 1024 * 1024; // 20 MB
-const AMBatchEventLimit = 500; // event size limit from sdk is 32KB => 15MB
-
const EVENTS_KEY_PATH = 'body.JSON.events';
const baseEndpoint = (destConfig) => {
@@ -79,82 +80,96 @@ const aliasEndpoint = (destConfig) => {
return retVal;
};
-function handleSessionIdUnderRoot(message) {
- const sessionId = get(message, 'session_id');
+const handleSessionIdUnderRoot = (sessionId) => {
if (typeof sessionId === 'string') {
- return sessionId.substr(sessionId.lastIndexOf(':') + 1, sessionId.length);
+ const extractedPart = sessionId.split(':').reverse();
+ if (!isValidInteger(extractedPart[0])) return -1;
+ return Number(extractedPart[0]);
}
- return sessionId;
-}
+ return Number(sessionId);
+};
-function handleSessionIdUnderContext(message) {
- let sessionId = get(message, 'context.sessionId');
- sessionId = Number(sessionId);
- if (Number.isNaN(sessionId)) return -1;
- return sessionId;
-}
+const handleSessionIdUnderContext = (sessionId) => {
+ if (!isValidInteger(sessionId)) return -1;
+ return Number(sessionId);
+};
-function getSessionId(message) {
- return get(message, 'session_id')
- ? handleSessionIdUnderRoot(message)
- : get(message, 'context.sessionId')
- ? handleSessionIdUnderContext(message)
- : -1;
-}
+const checkForJSONAndUserIdLengthAndDeviceId = (jsonBody, userId, deviceId) =>
+ Object.keys(jsonBody).length === 0 ||
+ (userId &&
+ userId.length < 5 &&
+ (!batchEventsWithUserIdLengthLowerThanFive ||
+ (batchEventsWithUserIdLengthLowerThanFive && !deviceId)));
+const getSessionId = (message) => {
+ let sessionId = -1;
+ const rootSessionId = get(message, 'session_id');
+ if (rootSessionId) {
+ sessionId = handleSessionIdUnderRoot(rootSessionId);
+ if (sessionId !== -1) {
+ return sessionId;
+ }
+ }
+ const contextSessionId = get(message, 'context.sessionId');
+ if (contextSessionId) {
+ sessionId = handleSessionIdUnderContext(contextSessionId);
+ }
+ return sessionId;
+};
-function addMinIdlength() {
- return { min_id_length: 1 };
-}
+const addMinIdlength = () => ({ min_id_length: 1 });
-function setPriceQuanityInPayload(message, rawPayload) {
+const setPriceQuanityInPayload = (message, rawPayload) => {
let price;
let quantity;
- if (isDefinedAndNotNull(message.properties.price)) {
+ if (isDefinedAndNotNull(message.properties?.price)) {
price = message.properties.price;
- quantity = message.properties.quantity || 1;
+ quantity = message.properties?.quantity || 1;
} else {
- price = message.properties.revenue;
+ price = message.properties?.revenue;
quantity = 1;
}
rawPayload.price = price;
rawPayload.quantity = quantity;
- rawPayload.revenue = message.properties.revenue;
+ rawPayload.revenue = message.properties?.revenue;
return rawPayload;
-}
+};
-function createRevenuePayload(message, rawPayload) {
- rawPayload.productId = message.properties.product_id;
+const createRevenuePayload = (message, rawPayload) => {
+ rawPayload.productId = message.properties?.product_id;
rawPayload.revenueType =
- message.properties.revenueType || message.properties.revenue_type || 'Purchased';
+ message.properties?.revenueType || message.properties?.revenue_type || 'Purchased';
rawPayload = setPriceQuanityInPayload(message, rawPayload);
return rawPayload;
-}
+};
-function updateTraitsObject(property, traitsObject, actionKey) {
+const updateTraitsObject = (property, traitsObject, actionKey) => {
const propertyToUpdate = getValueFromMessage(traitsObject, property);
if (traitsObject[actionKey] && property && typeof property === 'string') {
traitsObject[actionKey][property] = propertyToUpdate;
deleteObjectProperty(traitsObject, property);
}
return traitsObject;
-}
+};
-function prepareTraitsConfig(configPropertyTrait, actionKey, traitsObject) {
+const prepareTraitsConfig = (configPropertyTrait, actionKey, traitsObject) => {
traitsObject[actionKey] = {};
configPropertyTrait.forEach((traitsElement) => {
- const property = traitsElement.traits;
+ const property = traitsElement?.traits;
traitsObject = updateTraitsObject(property, traitsObject, actionKey);
});
- if (Object.keys(traitsObject[actionKey]).length === 0) {
+ if (
+ typeof traitsObject?.[actionKey] === 'object' &&
+ Object.keys(traitsObject?.[actionKey] || {})?.length === 0
+ ) {
delete traitsObject[actionKey];
}
return traitsObject;
-}
+};
-function handleTraits(messageTrait, destination) {
+const handleTraits = (messageTrait, destination) => {
let traitsObject = JSON.parse(JSON.stringify(messageTrait));
- if (destination.Config.traitsToIncrement) {
+ if (destination.Config?.traitsToIncrement) {
const actionKey = '$add';
traitsObject = prepareTraitsConfig(
destination.Config.traitsToIncrement,
@@ -162,29 +177,41 @@ function handleTraits(messageTrait, destination) {
traitsObject,
);
}
- if (destination.Config.traitsToSetOnce) {
+ if (destination.Config?.traitsToSetOnce) {
const actionKey = '$setOnce';
traitsObject = prepareTraitsConfig(destination.Config.traitsToSetOnce, actionKey, traitsObject);
}
- if (destination.Config.traitsToAppend) {
+ if (destination.Config?.traitsToAppend) {
const actionKey = '$append';
traitsObject = prepareTraitsConfig(destination.Config.traitsToAppend, actionKey, traitsObject);
}
- if (destination.Config.traitsToPrepend) {
+ if (destination.Config?.traitsToPrepend) {
const actionKey = '$prepend';
traitsObject = prepareTraitsConfig(destination.Config.traitsToPrepend, actionKey, traitsObject);
}
return traitsObject;
-}
+};
+
+const getScreenevTypeAndUpdatedProperties = (message, CATEGORY_KEY) => {
+ const name = message.name || message.event || get(message, CATEGORY_KEY);
+ const updatedName = name ? `${name} ` : '';
+ return {
+ eventType: `Viewed ${updatedName}Screen`,
+ updatedProperties: {
+ ...message.properties,
+ name,
+ },
+ };
+};
-function handleMappingJsonObject(
+const handleMappingJsonObject = (
mappingJson,
sourceKey,
validatePayload,
payload,
message,
Config,
-) {
+) => {
const { isFunc, funcName, outKey } = mappingJson[sourceKey];
if (isFunc) {
if (validatePayload) {
@@ -203,150 +230,242 @@ function handleMappingJsonObject(
if (isDefinedAndNotNull(data)) {
set(payload, outKey, data);
delete message.traits[outKey];
- } else {
- // get the destKey/outKey value from calling the util function
- set(payload, outKey, AMUtils[funcName](message, sourceKey, Config));
+ return;
}
+ // get the destKey/outKey value from calling the util function
+ set(payload, outKey, AMUtils[funcName](message, sourceKey, Config));
}
}
-}
+};
-function updateConfigProperty(message, payload, mappingJson, validatePayload, Config) {
+const updateConfigProperty = (message, payload, mappingJson, validatePayload, Config) => {
const sourceKeys = Object.keys(mappingJson);
sourceKeys.forEach((sourceKey) => {
// check if custom processing is required on the payload sourceKey ==> destKey
if (typeof mappingJson[sourceKey] === 'object') {
handleMappingJsonObject(mappingJson, sourceKey, validatePayload, payload, message, Config);
- } else {
- // For common config
- if (validatePayload) {
- // if data is present in traits assign
- const messageData = get(message.traits, mappingJson[sourceKey]);
- if (isDefinedAndNotNull(messageData)) {
- set(payload, mappingJson[sourceKey], messageData);
- } else {
- const data = get(payload, mappingJson[sourceKey]);
- if (!isDefinedAndNotNull(data)) {
- const val = get(message, sourceKey);
- if (val || val === false || val === 0) {
- set(payload, mappingJson[sourceKey], val);
- }
+ } else if (validatePayload) {
+ // if data is present in traits assign
+ const messageData = get(message.traits, mappingJson[sourceKey]);
+ if (isDefinedAndNotNull(messageData)) {
+ set(payload, mappingJson[sourceKey], messageData);
+ } else {
+ const data = get(payload, mappingJson[sourceKey]);
+ if (!isDefinedAndNotNull(data)) {
+ const val = get(message, sourceKey);
+ if (val || val === false || val === 0) {
+ set(payload, mappingJson[sourceKey], val);
}
}
+ }
+ } else {
+ const data = get(message.traits, mappingJson[sourceKey]);
+ if (isDefinedAndNotNull(data)) {
+ set(payload, mappingJson[sourceKey], data);
} else {
- const data = get(message.traits, mappingJson[sourceKey]);
- if (isDefinedAndNotNull(data)) {
- set(payload, mappingJson[sourceKey], data);
- } else {
- set(payload, mappingJson[sourceKey], get(message, sourceKey));
- }
+ set(payload, mappingJson[sourceKey], get(message, sourceKey));
}
}
});
-}
+};
+const identifyBuilder = (message, destination, rawPayload) => {
+ // update payload user_properties from userProperties/traits/context.traits/nested traits of Rudder message
+ // traits like address converted to top level user properties (think we can skip this extra processing as AM supports nesting upto 40 levels)
+ let traits = getFieldValueFromMessage(message, 'traits');
+ if (traits) {
+ traits = handleTraits(traits, destination);
+ }
+ rawPayload.user_properties = {
+ ...rawPayload.user_properties,
+ ...message.userProperties,
+ };
+ if (traits) {
+ Object.keys(traits).forEach((trait) => {
+ if (SpecedTraits.includes(trait)) {
+ const mapping = TraitsMapping[trait];
+ Object.keys(mapping).forEach((key) => {
+ const checkKey = get(rawPayload.user_properties, key);
+ // this is done only if we want to add default values under address to the user_properties
+ // these values are also sent to the destination at the top level.
+ if (!isDefinedAndNotNull(checkKey)) {
+ set(rawPayload, `user_properties.${key}`, get(traits, mapping[key]));
+ }
+ });
+ } else {
+ set(rawPayload, `user_properties.${trait}`, get(traits, trait));
+ }
+ });
+ }
+ return rawPayload;
+};
+
+const getDefaultResponseData = (message, rawPayload, evType, groupInfo) => {
+ const traits = getFieldValueFromMessage(message, 'traits');
+ set(rawPayload, 'event_properties', message.properties);
+
+ if (traits) {
+ rawPayload.user_properties = {
+ ...rawPayload.user_properties,
+ ...traits,
+ };
+ }
-function getResponseData(evType, destination, rawPayload, message, groupInfo) {
- let endpoint = defaultEndpoint(destination.Config);
- let traits;
+ rawPayload.event_type = evType;
+ rawPayload.user_id = message.userId;
+ if (message.isRevenue) {
+ // making the revenue payload
+ rawPayload = createRevenuePayload(message, rawPayload);
+ // deleting the properties price, product_id, quantity and revenue from event_properties since it is already in root
+ if (rawPayload.event_properties) {
+ delete rawPayload.event_properties.price;
+ delete rawPayload.event_properties.product_id;
+ delete rawPayload.event_properties.quantity;
+ delete rawPayload.event_properties.revenue;
+ }
+ }
+ const groups = groupInfo && cloneDeep(groupInfo);
+ return { groups, rawPayload };
+};
+const getResponseData = (evType, destination, rawPayload, message, groupInfo) => {
let groups;
switch (evType) {
case EventType.IDENTIFY:
+ // event_type for identify event is $identify
+ rawPayload.event_type = IDENTIFY_AM;
+ identifyBuilder(message, destination, rawPayload);
+ break;
case EventType.GROUP:
- endpoint = defaultEndpoint(destination.Config);
// event_type for identify event is $identify
rawPayload.event_type = IDENTIFY_AM;
-
- if (evType === EventType.IDENTIFY) {
- // update payload user_properties from userProperties/traits/context.traits/nested traits of Rudder message
- // traits like address converted to top level user properties (think we can skip this extra processing as AM supports nesting upto 40 levels)
- traits = getFieldValueFromMessage(message, 'traits');
- if (traits) {
- traits = handleTraits(traits, destination);
- }
- rawPayload.user_properties = {
- ...rawPayload.user_properties,
- ...message.userProperties,
- };
- if (traits) {
- Object.keys(traits).forEach((trait) => {
- if (SpecedTraits.includes(trait)) {
- const mapping = TraitsMapping[trait];
- Object.keys(mapping).forEach((key) => {
- const checkKey = get(rawPayload.user_properties, key);
- // this is done only if we want to add default values under address to the user_properties
- // these values are also sent to the destination at the top level.
- if (!isDefinedAndNotNull(checkKey)) {
- set(rawPayload, `user_properties.${key}`, get(traits, mapping[key]));
- }
- });
- } else {
- set(rawPayload, `user_properties.${trait}`, get(traits, trait));
- }
- });
- }
- }
-
- if (
- evType === EventType.GROUP && // for Rudder group call, update the user_properties with group info
- // Refer (1.)
- groupInfo &&
- groupInfo.group_type &&
- groupInfo.group_value
- ) {
+ // for Rudder group call, update the user_properties with group info
+ if (groupInfo?.group_type && groupInfo?.group_value) {
groups = {};
groups[groupInfo.group_type] = groupInfo.group_value;
set(rawPayload, `user_properties.${[groupInfo.group_type]}`, groupInfo.group_value);
}
break;
case EventType.ALIAS:
- endpoint = aliasEndpoint(destination.Config);
break;
default:
- traits = getFieldValueFromMessage(message, 'traits');
- set(rawPayload, 'event_properties', message.properties);
-
- if (traits) {
- rawPayload.user_properties = {
- ...rawPayload.user_properties,
- ...traits,
- };
- }
+ ({ groups, rawPayload } = getDefaultResponseData(message, rawPayload, evType, groupInfo));
+ }
+ return { rawPayload, groups };
+};
- rawPayload.event_type = evType;
- rawPayload.user_id = message.userId;
- if (message.isRevenue) {
- // making the revenue payload
- rawPayload = createRevenuePayload(message, rawPayload);
- // deleting the properties price, product_id, quantity and revenue from event_properties since it is already in root
- if (rawPayload.event_properties) {
- delete rawPayload.event_properties.price;
- delete rawPayload.event_properties.product_id;
- delete rawPayload.event_properties.quantity;
- delete rawPayload.event_properties.revenue;
- }
- }
- groups = groupInfo && Object.assign(groupInfo);
+const buildPayloadForMobileChannel = (message, destination, payload) => {
+ if (!destination.Config.mapDeviceBrand) {
+ set(payload, 'device_brand', get(message, 'context.device.manufacturer'));
+ }
+
+ const deviceId = get(message, 'context.device.id');
+ const platform = get(message, 'context.device.type');
+ const advertId = get(message, 'context.device.advertisingId');
+
+ if (platform) {
+ if (isAppleFamily(platform)) {
+ set(payload, 'idfa', advertId);
+ set(payload, 'idfv', deviceId);
+ } else if (platform.toLowerCase() === 'android') {
+ set(payload, 'adid', advertId);
+ }
+ }
+};
+const nonAliasResponsebuilder = (
+ message,
+ payload,
+ destination,
+ evType,
+ groupInfo,
+ rootElementName,
+) => {
+ const respList = [];
+ const addOptions = 'options';
+ const response = defaultRequestConfig();
+ const groupResponse = defaultRequestConfig();
+ const endpoint = defaultEndpoint(destination.Config);
+ if (message.channel === 'mobile') {
+ buildPayloadForMobileChannel(message, destination, payload);
}
- return { endpoint, rawPayload, groups };
-}
+ payload.time = new Date(getFieldValueFromMessage(message, 'timestamp')).getTime();
-function responseBuilderSimple(
+ // send user_id only when present, for anonymous users not required
+ if (message.userId && message.userId !== null) {
+ payload.user_id = message.userId;
+ }
+ payload.session_id = getSessionId(message);
+
+ updateConfigProperty(
+ message,
+ payload,
+ mappingConfig[ConfigCategory.COMMON_CONFIG.name],
+ true,
+ destination.Config,
+ );
+
+ // we are not fixing the verson for android specifically any more because we've put a fix in iOS SDK
+ // for correct versionName
+ // ====================
+ // fixVersion(payload, message);
+
+ if (payload.user_properties) {
+ delete payload.user_properties.city;
+ delete payload.user_properties.country;
+ if (payload.user_properties.address) {
+ delete payload.user_properties.address.city;
+ delete payload.user_properties.address.country;
+ }
+ }
+
+ if (!payload.user_id && !payload.device_id) {
+ logger.debug('Either of user ID or device ID fields must be specified');
+ throw new InstrumentationError('Either of user ID or device ID fields must be specified');
+ }
+
+ payload.ip = getParsedIP(message);
+ payload.library = 'rudderstack';
+ payload = removeUndefinedAndNullValues(payload);
+ response.endpoint = endpoint;
+ response.method = defaultPostRequestConfig.requestMethod;
+ response.headers = {
+ 'Content-Type': JSON_MIME_TYPE,
+ };
+ response.userId = message.anonymousId;
+ response.body.JSON = {
+ api_key: destination.Config.apiKey,
+ [rootElementName]: [payload],
+ [addOptions]: addMinIdlength(),
+ };
+ respList.push(response);
+
+ // https://developers.amplitude.com/docs/group-identify-api
+ // Refer (1.), Rudder group call updates group propertiees.
+ if (evType === EventType.GROUP && groupInfo) {
+ groupResponse.method = defaultPostRequestConfig.requestMethod;
+ groupResponse.endpoint = groupEndpoint(destination.Config);
+ let groupPayload = cloneDeep(groupInfo);
+ groupResponse.userId = message.anonymousId;
+ groupPayload = removeUndefinedValues(groupPayload);
+ groupResponse.body.FORM = {
+ api_key: destination.Config.apiKey,
+ identification: [JSON.stringify(groupPayload)],
+ };
+ respList.push(groupResponse);
+ }
+ return respList;
+};
+
+const responseBuilderSimple = (
groupInfo,
rootElementName,
message,
evType,
mappingJson,
destination,
-) {
- let rawPayload = {};
- const addOptions = 'options';
+) => {
+ const rawPayload = {};
const respList = [];
- const response = defaultRequestConfig();
- const groupResponse = defaultRequestConfig();
const aliasResponse = defaultRequestConfig();
- let endpoint = defaultEndpoint(destination.Config);
-
if (
EventType.IDENTIFY && // If mapped to destination, Add externalId to traits
get(message, MappedToDestinationKey)
@@ -375,7 +494,7 @@ function responseBuilderSimple(
const oldKeys = Object.keys(campaign);
// appends utm_ prefix to all the keys of campaign object. For example the `name` key in campaign object will be changed to `utm_name`
oldKeys.forEach((oldKey) => {
- Object.assign(campaign, { [`utm_${oldKey}`]: campaign[oldKey] });
+ campaign[`utm_${oldKey}`] = campaign[oldKey];
delete campaign[oldKey];
});
@@ -390,14 +509,13 @@ function responseBuilderSimple(
};
const respData = getResponseData(evType, destination, rawPayload, message, groupInfo);
- const { groups } = respData;
- ({ endpoint, rawPayload } = respData);
+ const { groups, rawPayload: updatedRawPayload } = respData;
// for https://api.amplitude.com/2/httpapi , pass the "groups" key
// refer (1.) for passing "groups" for Rudder group call
// https://developers.amplitude.com/docs/http-api-v2#schemaevent
- set(rawPayload, 'groups', groups);
- let payload = removeUndefinedValues(rawPayload);
+ set(updatedRawPayload, 'groups', groups);
+ let payload = removeUndefinedValues(updatedRawPayload);
let unmapUserId;
if (evType === EventType.ALIAS) {
// By default (1.), Alias config file populates user_id and global_user_id
@@ -419,113 +537,59 @@ function responseBuilderSimple(
};
respList.push(aliasResponse);
} else {
- if (message.channel === 'mobile') {
- if (!destination.Config.mapDeviceBrand) {
- set(payload, 'device_brand', get(message, 'context.device.manufacturer'));
- }
-
- const deviceId = get(message, 'context.device.id');
- const platform = get(message, 'context.device.type');
- const advertId = get(message, 'context.device.advertisingId');
-
- if (platform) {
- if (isAppleFamily(platform)) {
- set(payload, 'idfa', advertId);
- set(payload, 'idfv', deviceId);
- } else if (platform.toLowerCase() === 'android') {
- set(payload, 'adid', advertId);
- }
- }
- }
-
- payload.time = new Date(getFieldValueFromMessage(message, 'timestamp')).getTime();
-
- // send user_id only when present, for anonymous users not required
- if (
- message.userId &&
- message.userId !== '' &&
- message.userId !== 'null' &&
- message.userId !== null
- ) {
- payload.user_id = message.userId;
- }
- payload.session_id = getSessionId(message);
-
- updateConfigProperty(
+ return nonAliasResponsebuilder(
message,
payload,
- mappingConfig[ConfigCategory.COMMON_CONFIG.name],
- true,
- destination.Config,
+ destination,
+ evType,
+ groupInfo,
+ rootElementName,
);
+ }
+ return respList;
+};
- // we are not fixing the verson for android specifically any more because we've put a fix in iOS SDK
- // for correct versionName
- // ====================
- // fixVersion(payload, message);
-
- if (payload.user_properties) {
- delete payload.user_properties.city;
- delete payload.user_properties.country;
- if (payload.user_properties.address) {
- delete payload.user_properties.address.city;
- delete payload.user_properties.address.country;
- }
- }
-
- if (!payload.user_id && !payload.device_id) {
- logger.debug('Either of user ID or device ID fields must be specified');
- throw new InstrumentationError('Either of user ID or device ID fields must be specified');
- }
-
- payload.ip = getParsedIP(message);
- payload.library = 'rudderstack';
- payload = removeUndefinedAndNullValues(payload);
- response.endpoint = endpoint;
- response.method = defaultPostRequestConfig.requestMethod;
- response.headers = {
- 'Content-Type': JSON_MIME_TYPE,
- };
- response.userId = message.anonymousId;
- response.body.JSON = {
- api_key: destination.Config.apiKey,
- [rootElementName]: [payload],
- [addOptions]: addMinIdlength(),
- };
- respList.push(response);
-
- // https://developers.amplitude.com/docs/group-identify-api
- // Refer (1.), Rudder group call updates group propertiees.
- if (evType === EventType.GROUP && groupInfo) {
- groupResponse.method = defaultPostRequestConfig.requestMethod;
- groupResponse.endpoint = groupEndpoint(destination.Config);
- let groupPayload = Object.assign(groupInfo);
- groupResponse.userId = message.anonymousId;
- groupPayload = removeUndefinedValues(groupPayload);
- groupResponse.body.FORM = {
- api_key: destination.Config.apiKey,
- identification: [JSON.stringify(groupPayload)],
- };
- respList.push(groupResponse);
+const getGroupInfo = (destination, groupInfo, groupTraits) => {
+ const { groupTypeTrait, groupValueTrait } = destination.Config;
+ if (groupTypeTrait && groupValueTrait) {
+ let updatedGroupInfo = { ...groupInfo };
+ const groupTypeValue = get(groupTraits, groupTypeTrait);
+ const groupNameValue = get(groupTraits, groupValueTrait);
+ // since the property updates on group at https://api2.amplitude.com/groupidentify
+ // expects a string group name and value , so error out if the keys are not primitive
+ // Note: This different for groups object at https://api.amplitude.com/2/httpapi where the
+ // group value can be array of strings as well.
+ if (
+ groupTypeValue &&
+ typeof groupTypeValue === 'string' &&
+ groupNameValue &&
+ (typeof groupNameValue === 'string' || typeof groupNameValue === 'number')
+ ) {
+ updatedGroupInfo = {};
+ updatedGroupInfo.group_type = groupTypeValue;
+ updatedGroupInfo.group_value = groupNameValue;
+ // passing the entire group traits without deleting the above keys
+ updatedGroupInfo.group_properties = groupTraits;
+ return updatedGroupInfo;
}
+ logger.debug('Group call parameters are not valid');
+ throw new InstrumentationError('Group call parameters are not valid');
}
-
- return respList;
-}
+ return groupInfo;
+};
+const getUpdatedPageNameWithoutUserDefinedPageEventName = (name, message, CATEGORY_KEY) =>
+ name || get(message, CATEGORY_KEY) ? `${name || get(message, CATEGORY_KEY)} ` : undefined;
// Generic process function which invokes specific handler functions depending on message type
// and event type where applicable
-function processSingleMessage(message, destination) {
+const processSingleMessage = (message, destination) => {
let payloadObjectName = 'events';
let evType;
- let groupTraits;
- let groupTypeTrait;
- let groupValueTrait;
// It is expected that Rudder alias. identify group calls won't have this set
// To be used for track/page calls to associate the event to a group in AM
let groupInfo = get(message, 'integrations.Amplitude.groups') || undefined;
let category = ConfigCategory.DEFAULT;
-
+ const { name, event, properties } = message;
const messageType = message.type.toLowerCase();
const CATEGORY_KEY = 'properties.category';
const { useUserDefinedPageEventName, userProvidedPageEventString } = destination.Config;
@@ -545,27 +609,34 @@ function processSingleMessage(message, destination) {
.trim();
evType =
userProvidedPageEventString.trim() === ''
- ? message.name
+ ? name
: userProvidedPageEventString
.trim()
.replaceAll(/{{([^{}]+)}}/g, get(message, getMessagePath));
} else {
- evType = `Viewed ${message.name || get(message, CATEGORY_KEY) || ''} Page`;
+ const updatedName = getUpdatedPageNameWithoutUserDefinedPageEventName(
+ name,
+ message,
+ CATEGORY_KEY,
+ );
+ evType = `Viewed ${updatedName || ''}Page`;
}
-
message.properties = {
- ...message.properties,
- name: message.name || get(message, CATEGORY_KEY),
+ ...properties,
+ name: name || get(message, CATEGORY_KEY),
};
category = ConfigCategory.PAGE;
break;
case EventType.SCREEN:
- evType = `Viewed ${message.name || message.event || get(message, CATEGORY_KEY) || ''} Screen`;
- message.properties = {
- ...message.properties,
- name: message.name || message.event || get(message, CATEGORY_KEY),
- };
- category = ConfigCategory.SCREEN;
+ {
+ const { eventType, updatedProperties } = getScreenevTypeAndUpdatedProperties(
+ message,
+ CATEGORY_KEY,
+ );
+ evType = eventType;
+ message.properties = updatedProperties;
+ category = ConfigCategory.SCREEN;
+ }
break;
case EventType.GROUP:
evType = 'group';
@@ -574,34 +645,13 @@ function processSingleMessage(message, destination) {
// read from group traits from message
// groupTraits => top level "traits" for JS SDK
// groupTraits => "context.traits" for mobile SDKs
- groupTraits = getFieldValueFromMessage(message, 'groupTraits');
+ groupInfo = getGroupInfo(
+ destination,
+ groupInfo,
+ getFieldValueFromMessage(message, 'groupTraits'),
+ );
// read destination config related group settings
// https://developers.amplitude.com/docs/group-identify-api
- groupTypeTrait = get(destination, 'Config.groupTypeTrait');
- groupValueTrait = get(destination, 'Config.groupValueTrait');
- if (groupTypeTrait && groupValueTrait) {
- const groupTypeValue = get(groupTraits, groupTypeTrait);
- const groupNameValue = get(groupTraits, groupValueTrait);
- // since the property updates on group at https://api2.amplitude.com/groupidentify
- // expects a string group name and value , so error out if the keys are not primitive
- // Note: This different for groups object at https://api.amplitude.com/2/httpapi where the
- // group value can be array of strings as well.
- if (
- groupTypeValue &&
- typeof groupTypeValue === 'string' &&
- groupNameValue &&
- (typeof groupNameValue === 'string' || typeof groupNameValue === 'number')
- ) {
- groupInfo = {};
- groupInfo.group_type = groupTypeValue;
- groupInfo.group_value = groupNameValue;
- // passing the entire group traits without deleting the above keys
- groupInfo.group_properties = groupTraits;
- } else {
- logger.debug('Group call parameters are not valid');
- throw new InstrumentationError('Group call parameters are not valid');
- }
- }
break;
case EventType.ALIAS:
evType = 'alias';
@@ -611,21 +661,19 @@ function processSingleMessage(message, destination) {
category = ConfigCategory.ALIAS;
break;
case EventType.TRACK:
- evType = message.event;
+ evType = event;
if (!isDefinedAndNotNullAndNotEmpty(evType)) {
- throw new InstrumentationError('message type not defined');
+ throw new InstrumentationError('Event not present. Please send event field');
}
if (
- message.properties &&
- isDefinedAndNotNull(message.properties.revenue) &&
- isDefinedAndNotNull(message.properties.revenue_type)
+ properties &&
+ isDefinedAndNotNull(properties?.revenue) &&
+ isDefinedAndNotNull(properties?.revenue_type)
) {
// if properties has revenue and revenue_type fields
// consider the event as revenue event directly
category = ConfigCategory.REVENUE;
- break;
}
-
break;
default:
logger.debug('could not determine type');
@@ -639,10 +687,10 @@ function processSingleMessage(message, destination) {
mappingConfig[category.name],
destination,
);
-}
+};
-function createProductPurchasedEvent(message, destination, product, counter) {
- const eventClonePurchaseProduct = JSON.parse(JSON.stringify(message));
+const createProductPurchasedEvent = (message, destination, product, counter) => {
+ const eventClonePurchaseProduct = cloneDeep(message);
eventClonePurchaseProduct.event = 'Product Purchased';
// In product purchased event event properties consists of the details of each product
@@ -654,17 +702,17 @@ function createProductPurchasedEvent(message, destination, product, counter) {
// need to modify the message id of each newly created event, as it is mapped to insert_id and that is used by Amplitude for dedup.
eventClonePurchaseProduct.messageId = `${message.messageId}-${counter}`;
return eventClonePurchaseProduct;
-}
+};
-function isProductArrayInPayload(message) {
+const isProductArrayInPayload = (message) => {
const isProductArray =
- (message.properties.products &&
+ (message.properties?.products &&
Array.isArray(message.properties.products) &&
message.properties.products.length > 0) === true;
return isProductArray;
-}
+};
-function getProductPurchasedEvents(message, destination) {
+const getProductPurchasedEvents = (message, destination) => {
const productPurchasedEvents = [];
if (isProductArrayInPayload(message)) {
let counter = 0;
@@ -682,16 +730,16 @@ function getProductPurchasedEvents(message, destination) {
});
}
return productPurchasedEvents;
-}
+};
-function trackRevenueEvent(message, destination) {
+const trackRevenueEvent = (message, destination) => {
let sendEvents = [];
- const originalEvent = JSON.parse(JSON.stringify(message));
+ const originalEvent = cloneDeep(message);
if (destination.Config.trackProductsOnce === false) {
if (isProductArrayInPayload(message)) {
// when trackProductsOnce false no product array present
- delete originalEvent.properties.products;
+ delete originalEvent.properties?.products;
} else {
// when product array is not there in payload, will track the revenue of the original event.
originalEvent.isRevenue = true;
@@ -719,16 +767,19 @@ function trackRevenueEvent(message, destination) {
}
}
return sendEvents;
-}
+};
-function process(event) {
+const process = (event) => {
const respList = [];
const { message, destination } = event;
- const messageType = message.type.toLowerCase();
+ const messageType = message.type?.toLowerCase();
const toSendEvents = [];
+ if (!destination?.Config?.apiKey) {
+ throw new ConfigurationError('No API Key is Found. Please Configure API key from dashbaord');
+ }
if (messageType === EventType.TRACK) {
const { properties } = message;
- if (properties && isDefinedAndNotNull(properties.revenue)) {
+ if (isDefinedAndNotNull(properties?.revenue)) {
const revenueEvents = trackRevenueEvent(message, destination);
revenueEvents.forEach((revenueEvent) => {
toSendEvents.push(revenueEvent);
@@ -744,9 +795,9 @@ function process(event) {
respList.push(...processSingleMessage(sendEvent, destination));
});
return respList;
-}
+};
-function getBatchEvents(message, destination, metadata, batchEventResponse) {
+const getBatchEvents = (message, destination, metadata, batchEventResponse) => {
let batchComplete = false;
const batchEventArray = get(batchEventResponse, 'batchedRequest.body.JSON.events') || [];
const batchEventJobs = get(batchEventResponse, 'metadata') || [];
@@ -760,18 +811,19 @@ function getBatchEvents(message, destination, metadata, batchEventResponse) {
: incomingMessageEvent;
const userId = incomingMessageEvent.user_id;
- // delete the userId as it is less than 5 as AM is giving 400
- // that is not a documented behviour where it states if either deviceid or userid is present
- // batch request won't return 400
- // {
- // "code": 400,
- // "events_with_invalid_id_lengths": {
- // "user_id": [
- // 0
- // ]
- // },
- // "error": "Invalid id length for user_id or device_id"
- // }
+ /* delete the userId as it is less than 5 as AM is giving 400
+ that is not a documented behviour where it states if either deviceid or userid is present
+ batch request won't return 400
+ {
+ "code": 400,
+ "events_with_invalid_id_lengths": {
+ "user_id": [
+ 0
+ ]
+ },
+ "error": "Invalid id length for user_id or device_id"
+ }
+ */
if (batchEventsWithUserIdLengthLowerThanFive && userId && userId.length < 5) {
delete incomingMessageEvent.user_id;
}
@@ -782,10 +834,7 @@ function getBatchEvents(message, destination, metadata, batchEventResponse) {
if (batchEventArray.length === 0) {
if (JSON.stringify(incomingMessageJSON).length < AMBatchSizeLimit) {
delete message.body.JSON.options;
- batchEventResponse = Object.assign(batchEventResponse, {
- batchedRequest: message,
- });
-
+ batchEventResponse.batchedRequest = message;
set(batchEventResponse, 'batchedRequest.endpoint', BATCH_ENDPOINT);
batchEventResponse.metadata = [metadata];
}
@@ -807,16 +856,16 @@ function getBatchEvents(message, destination, metadata, batchEventResponse) {
}
}
return batchComplete;
-}
+};
-function batch(destEvents) {
+const getFirstEvent = (messageEvent) =>
+ messageEvent && Array.isArray(messageEvent) ? messageEvent[0] : messageEvent;
+const batch = (destEvents) => {
const respList = [];
let batchEventResponse = defaultBatchRequestConfig();
let response;
let isBatchComplete;
let jsonBody;
- let userId;
- let deviceId;
let messageEvent;
let destinationObject;
destEvents.forEach((ev) => {
@@ -824,18 +873,11 @@ function batch(destEvents) {
destinationObject = { ...destination };
jsonBody = get(message, 'body.JSON');
messageEvent = get(message, EVENTS_KEY_PATH);
- userId =
- messageEvent && Array.isArray(messageEvent)
- ? messageEvent[0].user_id
- : messageEvent
- ? messageEvent.user_id
- : undefined;
- deviceId =
- messageEvent && Array.isArray(messageEvent)
- ? messageEvent[0].device_id
- : messageEvent
- ? messageEvent.device_id
- : undefined;
+ const firstEvent = getFirstEvent(messageEvent);
+
+ const userId = firstEvent?.user_id ?? undefined;
+ const deviceId = firstEvent?.device_id ?? undefined;
+
// this case shold not happen and should be filtered already
// by the first pass of single event transformation
if (messageEvent && !userId && !deviceId) {
@@ -851,16 +893,13 @@ function batch(destEvents) {
respList.push(errorResponse);
return;
}
- // check if not a JSON body or (userId length < 5 && batchEventsWithUserIdLengthLowerThanFive is false) or
- // (batchEventsWithUserIdLengthLowerThanFive is true and userId is less than 5 but deviceId not present)
- // , send the event as is after batching
- if (
- Object.keys(jsonBody).length === 0 ||
- (!batchEventsWithUserIdLengthLowerThanFive && userId && userId.length < 5) ||
- (batchEventsWithUserIdLengthLowerThanFive && userId && userId.length < 5 && !deviceId)
- ) {
+ /* check if not a JSON body or (userId length < 5 && batchEventsWithUserIdLengthLowerThanFive is false) or
+ (batchEventsWithUserIdLengthLowerThanFive is true and userId is less than 5 but deviceId not present),
+ send the event as is after batching
+ */
+ if (checkForJSONAndUserIdLengthAndDeviceId(jsonBody, userId, deviceId)) {
response = defaultBatchRequestConfig();
- response = Object.assign(response, { batchedRequest: message });
+ response.batchedRequest = message;
response.metadata = [metadata];
response.destination = destinationObject;
respList.push(response);
@@ -868,8 +907,9 @@ function batch(destEvents) {
// check if the event can be pushed to an existing batch
isBatchComplete = getBatchEvents(message, destination, metadata, batchEventResponse);
if (isBatchComplete) {
- // if the batch is already complete, push it to response list
- // and push the event to a new batch
+ /* if the batch is already complete, push it to response list
+ and push the event to a new batch
+ */
batchEventResponse.destination = destinationObject;
respList.push({ ...batchEventResponse });
batchEventResponse = defaultBatchRequestConfig();
@@ -879,12 +919,12 @@ function batch(destEvents) {
}
});
// if there is some unfinished batch push it to response list
- if (isBatchComplete !== undefined && isBatchComplete === false) {
+ if (isDefinedAndNotNull(isBatchComplete) && !isBatchComplete) {
batchEventResponse.destination = destinationObject;
respList.push(batchEventResponse);
}
return respList;
-}
+};
const processRouterDest = async (inputs, reqMetadata) => {
const respList = await simpleProcessRouterDest(inputs, process, reqMetadata);
diff --git a/src/v0/destinations/am/utils.js b/src/v0/destinations/am/utils.js
index 33040c2146..b9925c20d8 100644
--- a/src/v0/destinations/am/utils.js
+++ b/src/v0/destinations/am/utils.js
@@ -13,65 +13,65 @@ const uaParser = require('@amplitude/ua-parser-js');
const logger = require('../../../logger');
const { isDefinedAndNotNull } = require('../../util');
-function getInfoFromUA(path, payload, defaultVal) {
+const getInfoFromUA = (path, payload, defaultVal) => {
const ua = get(payload, 'context.userAgent');
const devInfo = ua ? uaParser(ua) : {};
return get(devInfo, path) || defaultVal;
-}
+};
-function getOSName(payload, sourceKey) {
+const getOSName = (payload, sourceKey) => {
const payloadVal = get(payload, sourceKey);
if (payload.channel && payload.channel.toLowerCase() === 'web') {
return getInfoFromUA('browser.name', payload, payloadVal);
}
return payloadVal;
-}
+};
-function getOSVersion(payload, sourceKey) {
+const getOSVersion = (payload, sourceKey) => {
const payloadVal = get(payload, sourceKey);
if (payload.channel && payload.channel.toLowerCase() === 'web') {
return getInfoFromUA('browser.version', payload, payloadVal);
}
return payloadVal;
-}
+};
-function getDeviceModel(payload, sourceKey) {
+const getDeviceModel = (payload, sourceKey) => {
const payloadVal = get(payload, sourceKey);
if (payload.channel && payload.channel.toLowerCase() === 'web') {
return getInfoFromUA('os.name', payload, payloadVal);
}
return payloadVal;
-}
+};
-function getDeviceManufacturer(payload, sourceKey) {
+const getDeviceManufacturer = (payload, sourceKey) => {
const payloadVal = get(payload, sourceKey);
if (payload.channel && payload.channel.toLowerCase() === 'web') {
return getInfoFromUA('device.vendor', payload, payloadVal);
}
return payloadVal;
-}
+};
-function getPlatform(payload, sourceKey) {
+const getPlatform = (payload, sourceKey) => {
const payloadVal = get(payload, sourceKey);
return payload.channel
? payload.channel.toLowerCase() === 'web'
? 'Web'
: payloadVal
: payloadVal;
-}
+};
-function getBrand(payload, sourceKey, Config) {
+const getBrand = (payload, sourceKey, Config) => {
if (Config.mapDeviceBrand) {
const payloadVal = get(payload, sourceKey);
return payloadVal;
}
return undefined;
-}
+};
-function getEventId(payload, sourceKey) {
+const getEventId = (payload, sourceKey) => {
const eventId = get(payload, sourceKey);
if (isDefinedAndNotNull(eventId)) {
@@ -80,7 +80,7 @@ function getEventId(payload, sourceKey) {
} else return eventId;
}
return undefined;
-}
+};
module.exports = {
getOSName,
diff --git a/src/v0/destinations/customerio/transform.js b/src/v0/destinations/customerio/transform.js
index 5f953ee2f0..984fb7e67f 100644
--- a/src/v0/destinations/customerio/transform.js
+++ b/src/v0/destinations/customerio/transform.js
@@ -12,6 +12,7 @@ const {
adduserIdFromExternalId,
getFieldValueFromMessage,
handleRtTfSingleEventError,
+ validateEventName,
} = require('../../util');
const logger = require('../../../logger');
@@ -101,6 +102,7 @@ function processSingleMessage(message, destination) {
break;
case EventType.TRACK:
evType = 'event';
+ validateEventName(message.event);
evName = message.event;
break;
case EventType.ALIAS:
@@ -113,6 +115,7 @@ function processSingleMessage(message, destination) {
logger.error(`could not determine type ${messageType}`);
throw new InstrumentationError(`could not determine type ${messageType}`);
}
+ evName = evName ? String(evName) : evName;
const response = responseBuilder(message, evType, evName, destination, messageType);
// replace default domain with EU data center domainc for EU based account
diff --git a/src/v0/destinations/customerio/util.js b/src/v0/destinations/customerio/util.js
index 2e7f000fba..6b4dbc0e11 100644
--- a/src/v0/destinations/customerio/util.js
+++ b/src/v0/destinations/customerio/util.js
@@ -10,7 +10,6 @@ const {
defaultDeleteRequestConfig,
isAppleFamily,
validateEmail,
- validateEventType,
} = require('../../util');
const { EventType, SpecedTraits, TraitsMapping } = require('../../../constants');
@@ -288,7 +287,6 @@ const defaultResponseBuilder = (message, evName, userId, evType, destination, me
// 100 - len(`Viewed Screen`) = 86
trimmedEvName = `Viewed ${truncate(message.event || message.properties.name, 86)} Screen`;
} else {
- validateEventType(evName);
trimmedEvName = truncate(evName, 100);
}
// anonymous_id needs to be sent for anon track calls to provide information on which anon user is being tracked
diff --git a/src/v0/destinations/freshmarketer/config.js b/src/v0/destinations/freshmarketer/config.js
index f1018d439c..a0d6449c3a 100644
--- a/src/v0/destinations/freshmarketer/config.js
+++ b/src/v0/destinations/freshmarketer/config.js
@@ -4,23 +4,23 @@ const CONFIG_CATEGORIES = {
IDENTIFY: {
name: 'FRESHMARKETERIdentifyConfig',
type: 'identify',
- baseUrl: '.myfreshworks.com/crm/sales/api/contacts/upsert',
+ baseUrl: '/crm/sales/api/contacts/upsert',
},
GROUP: {
name: 'FRESHMARKETERGroupConfig',
type: 'group',
- baseUrlAccount: '.myfreshworks.com/crm/sales/api/sales_accounts/upsert',
- baseUrlList: '.myfreshworks.com/crm/sales/api/lists',
+ baseUrlAccount: '/crm/sales/api/sales_accounts/upsert',
+ baseUrlList: '/crm/sales/api/lists',
},
SALES_ACTIVITY: {
name: 'SalesActivityConfig',
- baseUrlCreate: '.myfreshworks.com/crm/sales/api/sales_activities',
- baseUrlListAll: '.myfreshworks.com/crm/sales/api/selector/sales_activity_types',
+ baseUrlCreate: '/crm/sales/api/sales_activities',
+ baseUrlListAll: '/crm/sales/api/selector/sales_activity_types',
},
};
-const DELETE_ENDPOINT = '.myfreshworks.com/crm/sales/api/contacts/';
-const LIFECYCLE_STAGE_ENDPOINT = '.myfreshworks.com/crm/sales/api/selector/lifecycle_stages';
+const DELETE_ENDPOINT = '/crm/sales/api/contacts/';
+const LIFECYCLE_STAGE_ENDPOINT = '/crm/sales/api/selector/lifecycle_stages';
const MAPPING_CONFIG = getMappingConfig(CONFIG_CATEGORIES, __dirname);
module.exports = {
diff --git a/src/v0/destinations/freshmarketer/utils.js b/src/v0/destinations/freshmarketer/utils.js
index 5b47bb9170..f7dcc46b06 100644
--- a/src/v0/destinations/freshmarketer/utils.js
+++ b/src/v0/destinations/freshmarketer/utils.js
@@ -203,7 +203,7 @@ const updateAccountWOContact = (payload, Config) => {
*/
const updateContactWithList = (userId, listId, Config) => {
const response = defaultRequestConfig();
- response.endpoint = `https://${Config.domain}.myfreshworks.com/crm/sales/api/lists/${listId}/add_contacts`;
+ response.endpoint = `https://${Config.domain}/crm/sales/api/lists/${listId}/add_contacts`;
response.headers = getHeaders(Config.apiKey);
response.body.JSON = {
ids: [userId],
diff --git a/src/v0/destinations/freshsales/config.js b/src/v0/destinations/freshsales/config.js
index c6ae4b8165..62f54c1297 100644
--- a/src/v0/destinations/freshsales/config.js
+++ b/src/v0/destinations/freshsales/config.js
@@ -4,23 +4,23 @@ const CONFIG_CATEGORIES = {
IDENTIFY: {
name: 'identifyConfig',
type: 'identify',
- baseUrl: '.myfreshworks.com/crm/sales/api/contacts/upsert',
+ baseUrl: '/crm/sales/api/contacts/upsert',
method: 'POST',
},
GROUP: {
name: 'groupConfig',
type: 'group',
- baseUrlAccount: '.myfreshworks.com/crm/sales/api/sales_accounts/upsert',
+ baseUrlAccount: '/crm/sales/api/sales_accounts/upsert',
method: 'POST',
},
SALES_ACTIVITY: {
name: 'SalesActivityConfig',
- baseUrlCreate: '.myfreshworks.com/crm/sales/api/sales_activities',
- baseUrlListAll: '.myfreshworks.com/crm/sales/api/selector/sales_activity_types',
+ baseUrlCreate: '/crm/sales/api/sales_activities',
+ baseUrlListAll: '/crm/sales/api/selector/sales_activity_types',
},
};
-const LIFECYCLE_STAGE_ENDPOINT = '.myfreshworks.com/crm/sales/api/selector/lifecycle_stages';
+const LIFECYCLE_STAGE_ENDPOINT = '/crm/sales/api/selector/lifecycle_stages';
const MAPPING_CONFIG = getMappingConfig(CONFIG_CATEGORIES, __dirname);
module.exports = {
diff --git a/src/v0/destinations/freshsales/transform.js b/src/v0/destinations/freshsales/transform.js
index cd7518a101..c1e18482ed 100644
--- a/src/v0/destinations/freshsales/transform.js
+++ b/src/v0/destinations/freshsales/transform.js
@@ -8,7 +8,7 @@ const {
defaultPostRequestConfig,
getValidDynamicFormConfig,
simpleProcessRouterDest,
- validateEventType,
+ validateEventName,
} = require('../../util');
const { InstrumentationError, TransformationError } = require('../../util/errorTypes');
const { CONFIG_CATEGORIES, MAPPING_CONFIG } = require('./config');
@@ -67,7 +67,6 @@ const identifyResponseBuilder = (message, { Config }) => {
* @returns
*/
const trackResponseBuilder = async (message, { Config }, event) => {
- validateEventType(event);
let payload;
const response = defaultRequestConfig();
@@ -125,9 +124,6 @@ const groupResponseBuilder = async (message, { Config }) => {
// Checks if there are any mapping events for the track event and returns them
function eventMappingHandler(message, destination) {
const event = get(message, 'event');
- if (!event) {
- throw new InstrumentationError('Event name is required');
- }
let { rudderEventsToFreshsalesEvents } = destination.Config;
const mappedEvents = new Set();
@@ -161,6 +157,7 @@ const processEvent = async (message, destination) => {
response = identifyResponseBuilder(message, destination);
break;
case EventType.TRACK: {
+ validateEventName(message.event);
const mappedEvents = eventMappingHandler(message, destination);
if (mappedEvents.length > 0) {
const respList = await Promise.all(
diff --git a/src/v0/destinations/klaviyo/util.js b/src/v0/destinations/klaviyo/util.js
index 4304edd78f..b31dafd78b 100644
--- a/src/v0/destinations/klaviyo/util.js
+++ b/src/v0/destinations/klaviyo/util.js
@@ -17,7 +17,6 @@ const { handleHttpRequest } = require('../../../adapters/network');
const { JSON_MIME_TYPE, HTTP_STATUS_CODES } = require('../../util/constant');
const { NetworkError, InstrumentationError } = require('../../util/errorTypes');
const { getDynamicErrorType } = require('../../../adapters/utils/networkUtils');
-const { client: errNotificationClient } = require('../../../util/errorNotifier');
const { BASE_ENDPOINT, MAPPING_CONFIG, CONFIG_CATEGORIES, MAX_BATCH_SIZE } = require('./config');
const REVISION_CONSTANT = '2023-02-22';
@@ -69,11 +68,6 @@ const getIdFromNewOrExistingProfile = async (endpoint, payload, requestOptions)
let statusCode = resp.status;
if (resp.status === 201 || resp.status === 409) {
// retryable error if the profile id is not found in the response
- errNotificationClient.notify(
- new Error('Klaviyo: ProfileId not found'),
- 'Profile Id not Found in the response',
- JSON.stringify(resp.response),
- );
statusCode = 500;
}
diff --git a/src/v0/destinations/monday/transform.js b/src/v0/destinations/monday/transform.js
index 34ada34780..37ee835e50 100644
--- a/src/v0/destinations/monday/transform.js
+++ b/src/v0/destinations/monday/transform.js
@@ -8,7 +8,7 @@ const {
removeUndefinedAndNullValues,
simpleProcessRouterDest,
getDestinationExternalID,
- validateEventType,
+ validateEventName,
} = require('../../util');
const {
ConfigurationError,
@@ -42,7 +42,7 @@ const trackResponseBuilder = async (message, { Config }) => {
const { apiToken } = Config;
let boardId = getDestinationExternalID(message, 'boardId');
const event = get(message, 'event');
- validateEventType(event);
+ validateEventName(event);
if (!boardId) {
boardId = Config.boardId;
}
diff --git a/src/v0/sources/revenuecat/mapping.json b/src/v0/sources/revenuecat/mapping.json
new file mode 100644
index 0000000000..541568b71b
--- /dev/null
+++ b/src/v0/sources/revenuecat/mapping.json
@@ -0,0 +1,10 @@
+[
+ {
+ "sourceKeys": "event.type",
+ "destKeys": "event"
+ },
+ {
+ "sourceKeys": "event.id",
+ "destKeys": "messageId"
+ }
+]
diff --git a/src/v0/sources/revenuecat/transform.js b/src/v0/sources/revenuecat/transform.js
new file mode 100644
index 0000000000..36944e10fa
--- /dev/null
+++ b/src/v0/sources/revenuecat/transform.js
@@ -0,0 +1,47 @@
+const { camelCase } = require('lodash');
+const moment = require('moment');
+const { removeUndefinedAndNullValues, isDefinedAndNotNull } = require('../../util');
+const Message = require('../message');
+
+function process(event) {
+ const message = new Message(`RevenueCat`);
+
+ // we are setting event type as track always
+ message.setEventType('track');
+
+ const properties = {};
+ // dump all event properties to message.properties after converting them to camelCase
+ if (event.event) {
+ Object.keys(event.event).forEach((key) => {
+ properties[camelCase(key)] = event.event[key];
+ });
+ message.setProperty('properties', properties);
+ }
+
+ // setting up app_user_id to externalId : revenuecatAppUserId
+ if (event?.event?.app_user_id) {
+ message.context.externalId = [
+ {
+ type: 'revenuecatAppUserId',
+ id: event?.event?.app_user_id,
+ },
+ ];
+ }
+
+ if (
+ isDefinedAndNotNull(event?.event?.event_timestamp_ms) &&
+ moment(event?.event?.event_timestamp_ms).isValid()
+ ) {
+ const validTimestamp = new Date(event.event.event_timestamp_ms).toISOString();
+ message.setProperty('originalTimestamp', validTimestamp);
+ message.setProperty('sentAt', validTimestamp);
+ }
+ message.event = event?.event?.type;
+ message.messageId = event?.event?.id;
+
+ // removing undefined and null values from message
+ removeUndefinedAndNullValues(message);
+ return message;
+}
+
+module.exports = { process };
diff --git a/src/v0/util/index.js b/src/v0/util/index.js
index bed515624c..d6f6621220 100644
--- a/src/v0/util/index.js
+++ b/src/v0/util/index.js
@@ -2059,7 +2059,17 @@ const getAuthErrCategoryFromStCode = (status) => {
return '';
};
-const validateEventType = (event) => {
+const isValidInteger = (value) => {
+ if (Number.isNaN(value) || !isDefinedAndNotNull(value)) {
+ return false;
+ }
+ if (typeof value === 'number' && value % 1 === 0) {
+ return true;
+ }
+ // Use a regular expression to check if the string is a valid integer or a valid floating-point number
+ return typeof value === 'string' ? /^-?\d+$/.test(value) : false;
+};
+const validateEventName = (event) => {
if (!event || typeof event !== 'string') {
throw new InstrumentationError('Event is a required field and should be a string');
}
@@ -2167,7 +2177,7 @@ module.exports = {
getDestAuthCacheInstance,
refinePayload,
validateEmail,
- validateEventType,
+ validateEventName,
validatePhoneWithCountryCode,
getEventReqMetadata,
isHybridModeEnabled,
@@ -2179,6 +2189,7 @@ module.exports = {
hasCircularReference,
getAuthErrCategoryFromErrDetailsAndStCode,
getAuthErrCategoryFromStCode,
+ isValidInteger,
isNewStatusCodesAccepted,
IsGzipSupported,
};
diff --git a/src/v0/util/index.test.js b/src/v0/util/index.test.js
index ce341e8187..e39c583aab 100644
--- a/src/v0/util/index.test.js
+++ b/src/v0/util/index.test.js
@@ -13,6 +13,7 @@ const functionNames = [
'batchMultiplexedEvents',
'removeUndefinedNullValuesAndEmptyObjectArray',
'groupEventsByType',
+ 'isValidInteger',
];
// Names of the utility functions to test which expects multiple arguments as values and not objects
diff --git a/src/v0/util/testdata/isValidInteger.json b/src/v0/util/testdata/isValidInteger.json
new file mode 100644
index 0000000000..be7be936a6
--- /dev/null
+++ b/src/v0/util/testdata/isValidInteger.json
@@ -0,0 +1,31 @@
+[
+ {
+ "description": "Number is undefined",
+ "output": false
+ },
+ {
+ "description": "Number in string format",
+ "input": "123",
+ "output": true
+ },
+ {
+ "description": "Normal Integer",
+ "input": 123,
+ "output": true
+ },
+ {
+ "description": "Float",
+ "input": 123.91,
+ "output": false
+ },
+ {
+ "description": "Float string",
+ "input": "123.00",
+ "output": false
+ },
+ {
+ "description": "Alphanumeric String",
+ "input": "abcd1234",
+ "output": false
+ }
+]
diff --git a/test/__tests__/data/adobe_analytics.json b/test/__tests__/data/adobe_analytics.json
index cfffccb8da..6361f92640 100644
--- a/test/__tests__/data/adobe_analytics.json
+++ b/test/__tests__/data/adobe_analytics.json
@@ -1010,7 +1010,6 @@
},
"messageId": "1578564113557-af022c68-429e-4af4-b99b-2b9174056383",
"properties": {
- "order_id": "1234",
"affiliation": "Apple Store",
"value": 20,
"revenue": 15.0,
@@ -1019,6 +1018,7 @@
"discount": 1.5,
"coupon": "ImagePro",
"currency": "USD",
+ "purchaseId": "p101",
"products": [
{
"product_id": "123",
@@ -1205,7 +1205,7 @@
"JSON": {},
"JSON_ARRAY": {},
"XML": {
- "payload": "17941080sales campaignwebUSD127.0.0.1en-US12341234Dalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)https://www.google.com/search?q=estore+bestsellerroottval001RudderLabs JavaScript SDKocheckout startedhttps://www.estore.com/best-seller/12020-01-09T10:01:53.558Zmktcloudid001scCheckoutGames;Monopoly;1;14.00,Games;UNO;2;6.90footlockerrudderstackpoc"
+ "payload": "17941080sales campaignwebUSD127.0.0.1en-USDalvik/2.1.0 (Linux; U; Android 9; Android SDK built for x86 Build/PSR1.180720.075)https://www.google.com/search?q=estore+bestsellerroottval001RudderLabs JavaScript SDKocheckout startedhttps://www.estore.com/best-seller/12020-01-09T10:01:53.558Zmktcloudid001p101scCheckoutGames;Monopoly;1;14.00,Games;UNO;2;6.90footlockerrudderstackpoc"
},
"FORM": {}
},
diff --git a/test/__tests__/data/am_batch_input.json b/test/__tests__/data/am_batch_input.json
index 64fe0b4ec7..5b0440babf 100644
--- a/test/__tests__/data/am_batch_input.json
+++ b/test/__tests__/data/am_batch_input.json
@@ -1,4 +1,67 @@
[
+ [
+ {
+ "message": {
+ "body": {
+ "XML": {},
+ "JSON_ARRAY": {},
+ "FORM": {},
+ "JSON": {
+ "events": [
+ {
+ "ip": "0.0.0.0",
+ "time": 1603132665557,
+ "os_name": "",
+ "app_name": "RudderLabs JavaScript SDK",
+ "language": "en-US",
+ "library": "rudderstack",
+ "event_type": "$identify",
+ "os_version": "",
+ "session_id": -1,
+ "app_version": "1.1.5",
+ "user_properties": {
+ "name": "some campaign",
+ "plan": "Open source",
+ "term": "keyword",
+ "test": "other value",
+ "email": "test@rudderstack.com",
+ "logins": 5,
+ "medium": "medium",
+ "source": "google",
+ "content": "some content",
+ "category": "SampleIdentify",
+ "createdAt": 1599264000
+ }
+ }
+ ],
+ "api_key": "4c7ed7573eb73517ee4c26ed4bde9a85",
+ "options": {
+ "min_id_length": 1
+ }
+ }
+ },
+ "type": "REST",
+ "files": {},
+ "method": "POST",
+ "params": {},
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "version": "1",
+ "endpoint": "https://api.eu.amplitude.com/2/httpapi"
+ },
+ "metadata": {
+ "job_id": 1
+ },
+ "destination": {
+ "ID": "a",
+ "url": "a",
+ "Config": {
+ "residencyServer": "EU"
+ }
+ }
+ }
+ ],
[
{
"message": {
diff --git a/test/__tests__/data/am_batch_output.json b/test/__tests__/data/am_batch_output.json
index dac6400585..32735b000f 100644
--- a/test/__tests__/data/am_batch_output.json
+++ b/test/__tests__/data/am_batch_output.json
@@ -1,4 +1,18 @@
[
+ [
+ {
+ "batched": false,
+ "error": "Both userId and deviceId cannot be undefined",
+ "metadata": {
+ "job_id": 1
+ },
+ "statTags": {
+ "errorCategory": "dataValidation",
+ "errorType": "instrumentation"
+ },
+ "statusCode": 400
+ }
+ ],
[
{
"batchedRequest": {
@@ -108,7 +122,9 @@
"JSON_ARRAY": {},
"FORM": {
"api_key": "4c7ed7573eb73517ee4c26ed4bde9a85",
- "mapping": ["{\"global_user_id\":\"newUserIdAlias\",\"user_id\":\"sampleusrRudder3\"}"]
+ "mapping": [
+ "{\"global_user_id\":\"newUserIdAlias\",\"user_id\":\"sampleusrRudder3\"}"
+ ]
},
"JSON": {}
},
@@ -361,7 +377,9 @@
"JSON_ARRAY": {},
"FORM": {
"api_key": "4c7ed7573eb73517ee4c26ed4bde9a85",
- "mapping": ["{\"global_user_id\":\"newUserIdAlias\",\"user_id\":\"sampleusrRudder3\"}"]
+ "mapping": [
+ "{\"global_user_id\":\"newUserIdAlias\",\"user_id\":\"sampleusrRudder3\"}"
+ ]
},
"JSON": {}
},
@@ -687,14 +705,29 @@
"DisplayName": "Braze",
"Config": {
"destConfig": {
- "android": ["useNativeSDK"],
- "defaultConfig": ["appKey", "dataCenter", "restApiKey"],
- "ios": ["useNativeSDK"],
- "web": ["useNativeSDK"]
+ "android": [
+ "useNativeSDK"
+ ],
+ "defaultConfig": [
+ "appKey",
+ "dataCenter",
+ "restApiKey"
+ ],
+ "ios": [
+ "useNativeSDK"
+ ],
+ "web": [
+ "useNativeSDK"
+ ]
},
"excludeKeys": [],
- "includeKeys": ["appKey", "dataCenter"],
- "secretKeys": ["restApiKey"],
+ "includeKeys": [
+ "appKey",
+ "dataCenter"
+ ],
+ "secretKeys": [
+ "restApiKey"
+ ],
"supportedSourceTypes": [
"android",
"ios",
@@ -760,7 +793,9 @@
"JSON_ARRAY": {},
"FORM": {
"api_key": "4c7ed7573eb73517ee4c26ed4bde9a85",
- "mapping": ["{\"global_user_id\":\"newUserIdAlias\",\"user_id\":\"sampleusrRudder3\"}"]
+ "mapping": [
+ "{\"global_user_id\":\"newUserIdAlias\",\"user_id\":\"sampleusrRudder3\"}"
+ ]
},
"JSON": {}
},
@@ -1043,7 +1078,9 @@
"JSON_ARRAY": {},
"FORM": {
"api_key": "4c7ed7573eb73517ee4c26ed4bde9a85",
- "mapping": ["{\"global_user_id\":\"newUserIdAlias\",\"user_id\":\"sampleusrRudder3\"}"]
+ "mapping": [
+ "{\"global_user_id\":\"newUserIdAlias\",\"user_id\":\"sampleusrRudder3\"}"
+ ]
},
"JSON": {}
},
@@ -1189,4 +1226,4 @@
}
}
]
-]
+]
\ No newline at end of file
diff --git a/test/__tests__/data/am_input.json b/test/__tests__/data/am_input.json
index 664894f7f5..3e5cde2cca 100644
--- a/test/__tests__/data/am_input.json
+++ b/test/__tests__/data/am_input.json
@@ -1,4 +1,214 @@
[
+ {
+ "message": {
+ "type": "track",
+ "sentAt": "2020-08-14T05:30:30.118Z",
+ "context": {
+ "source": "test",
+ "traits": {
+ "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1"
+ },
+ "library": {
+ "name": "rudder-sdk-ruby-sync",
+ "version": "1.0.6"
+ }
+ },
+ "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9",
+ "timestamp": "2020-08-14T05:30:30.118Z",
+ "properties": {
+ "tax": 2,
+ "total": 27.5,
+ "coupon": "hasbros",
+ "revenue": 48,
+ "revenue_type": "Purchased",
+ "quantity": 2,
+ "currency": "USD",
+ "discount": 2.5,
+ "order_id": "50314b8e9bcf000000000000",
+ "shipping": 3,
+ "subtotal": 22.5,
+ "affiliation": "Google Store",
+ "checkout_id": "fksdjfsdjfisjf9sdfjsd9f"
+ },
+ "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1",
+ "integrations": {
+ "S3": false,
+ "All": true
+ }
+ },
+ "destination": {
+ "Config": {
+ "apiKey": "abcde",
+ "groupTypeTrait": "email",
+ "groupValueTrait": "age",
+ "trackProductsOnce": true,
+ "trackRevenuePerProduct": false
+ }
+ }
+ },
+ {
+ "message": {
+ "type": "UNSUPPORTED-TYPE",
+ "event": "Order Completed",
+ "sentAt": "2020-08-14T05:30:30.118Z",
+ "context": {},
+ "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9",
+ "timestamp": "2020-08-14T05:30:30.118Z",
+ "properties": {},
+ "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1",
+ "integrations": {
+ "S3": false,
+ "All": true
+ }
+ },
+ "destination": {
+ "Config": {
+ "groupTypeTrait": "email",
+ "apiKey": "abcde",
+ "groupValueTrait": "age",
+ "trackProductsOnce": true,
+ "trackRevenuePerProduct": false
+ }
+ }
+ },
+ {
+ "message": {
+ "event": "Order Completed",
+ "sentAt": "2020-08-14T05:30:30.118Z",
+ "context": {},
+ "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9",
+ "timestamp": "2020-08-14T05:30:30.118Z",
+ "properties": {},
+ "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1",
+ "integrations": {
+ "S3": false,
+ "All": true
+ }
+ },
+ "destination": {
+ "Config": {
+ "groupTypeTrait": "email",
+ "groupValueTrait": "age",
+ "trackProductsOnce": true,
+ "trackRevenuePerProduct": false
+ }
+ }
+ },
+ {
+ "message": {
+ "type": "track",
+ "event": "Order Completed",
+ "sentAt": "2020-08-14T05:30:30.118Z",
+ "context": {
+ "source": "test",
+ "traits": {
+ "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1"
+ },
+ "library": {
+ "name": "rudder-sdk-ruby-sync",
+ "version": "1.0.6"
+ }
+ },
+ "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9",
+ "timestamp": "2020-08-14T05:30:30.118Z",
+ "properties": {
+ "tax": 2,
+ "total": 27.5,
+ "coupon": "hasbros",
+ "revenue": 48,
+ "revenue_type": "Purchased",
+ "quantity": 2,
+ "currency": "USD",
+ "discount": 2.5,
+ "order_id": "50314b8e9bcf000000000000",
+ "shipping": 3,
+ "subtotal": 22.5,
+ "affiliation": "Google Store",
+ "checkout_id": "fksdjfsdjfisjf9sdfjsd9f"
+ },
+ "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1",
+ "integrations": {
+ "S3": false,
+ "All": true
+ }
+ },
+ "destination": {
+ "Config": {
+ "apiKey": "abcde",
+ "groupTypeTrait": "email",
+ "groupValueTrait": "age",
+ "trackProductsOnce": true,
+ "trackRevenuePerProduct": false
+ }
+ }
+ },
+ {
+ "message": {
+ "type": "track",
+ "event": "Order Completed",
+ "sentAt": "2020-08-14T05:30:30.118Z",
+ "context": {
+ "source": "test",
+ "traits": {
+ "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1"
+ },
+ "library": {
+ "name": "rudder-sdk-ruby-sync",
+ "version": "1.0.6"
+ }
+ },
+ "messageId": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9",
+ "timestamp": "2020-08-14T05:30:30.118Z",
+ "properties": {
+ "tax": 2,
+ "total": 27.5,
+ "coupon": "hasbros",
+ "revenue": 48,
+ "quantity": 2,
+ "currency": "USD",
+ "discount": 2.5,
+ "order_id": "50314b8e9bcf000000000000",
+ "products": [
+ {
+ "sku": "45790-32",
+ "url": "https://www.example.com/product/path",
+ "name": "Monopoly: 3rd Edition",
+ "price": 19,
+ "category": "Games",
+ "quantity": 1,
+ "image_url": "https:///www.example.com/product/path.jpg",
+ "product_id": "507f1f77bcf86cd799439011"
+ },
+ {
+ "sku": "46493-32",
+ "name": "Uno Card Game",
+ "price": 3,
+ "category": "Games",
+ "quantity": 2,
+ "product_id": "505bd76785ebb509fc183733"
+ }
+ ],
+ "shipping": 3,
+ "subtotal": 22.5,
+ "affiliation": "Google Store",
+ "checkout_id": "fksdjfsdjfisjf9sdfjsd9f"
+ },
+ "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1",
+ "integrations": {
+ "S3": false,
+ "All": true
+ }
+ },
+ "destination": {
+ "Config": {
+ "apiKey": "abcde",
+ "groupTypeTrait": "email",
+ "groupValueTrait": "age",
+ "trackProductsOnce": true,
+ "trackRevenuePerProduct": false
+ }
+ }
+ },
{
"message": {
"channel": "web",
@@ -629,6 +839,91 @@
}
}
},
+ {
+ "message": {
+ "channel": "web",
+ "context": {
+ "app": {
+ "build": "1.0.0",
+ "name": "RudderLabs JavaScript SDK",
+ "namespace": "com.rudderlabs.javascript",
+ "version": "1.1.5"
+ },
+ "traits": {
+ "name": "Shehan Study",
+ "category": "SampleIdentify",
+ "email": "test@rudderstack.com",
+ "plan": "Open source",
+ "logins": 5,
+ "createdAt": 1599264000
+ },
+ "library": {
+ "name": "RudderLabs JavaScript SDK",
+ "version": "1.1.5"
+ },
+ "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",
+ "locale": "en-US",
+ "os": {
+ "name": "",
+ "version": ""
+ },
+ "screen": {
+ "density": 0.8999999761581421
+ },
+ "campaign": {
+ "source": "google",
+ "medium": "medium",
+ "term": "keyword",
+ "content": "some content",
+ "name": "some campaign",
+ "test": "other value"
+ },
+ "page": {
+ "path": "/destinations/amplitude",
+ "referrer": "",
+ "search": "",
+ "title": "",
+ "url": "https://docs.rudderstack.com/destinations/amplitude",
+ "category": "destination",
+ "initial_referrer": "https://docs.rudderstack.com",
+ "initial_referring_domain": "docs.rudderstack.com"
+ }
+ },
+ "type": "group",
+ "messageId": "e5034df0-a404-47b4-a463-76df99934fea",
+ "originalTimestamp": "2020-10-20T07:54:58.983Z",
+ "anonymousId": "my-anonymous-id-new",
+ "userId": "sampleusrRudder3",
+ "integrations": {
+ "All": true,
+ "Amplitude": {
+ "groups": {
+ "group_type": "Company",
+ "group_value": "ABC"
+ }
+ }
+ },
+ "groupId": "Sample_groupId23",
+ "traits": {
+ "KEY_3": {
+ "CHILD_KEY_92": "value_95",
+ "CHILD_KEY_102": "value_103"
+ },
+ "KEY_2": {
+ "CHILD_KEY_92": "value_95",
+ "CHILD_KEY_102": "value_103"
+ },
+ "name_trait": "Company",
+ "value_trait": "ABC"
+ },
+ "sentAt": "2020-10-20T07:54:58.983Z"
+ },
+ "destination": {
+ "Config": {
+ "apiKey": "abcde"
+ }
+ }
+ },
{
"message": {
"channel": "web",
@@ -698,7 +993,7 @@
"CHILD_KEY_102": "value_103"
},
"name_trait": "Company",
- "value_trait": "Comapny-ABC"
+ "value_trait": "ABC"
},
"sentAt": "2020-10-20T07:54:58.983Z"
},
@@ -779,7 +1074,9 @@
"CHILD_KEY_102": "value_103"
},
"name_trait": "Company",
- "value_trait": ["Comapny-ABC"]
+ "value_trait": [
+ "ABC"
+ ]
},
"sentAt": "2020-10-20T07:54:58.983Z"
},
@@ -3173,7 +3470,7 @@
"CHILD_KEY_102": "value_103"
},
"name_trait": "Company",
- "value_trait": "Comapny-ABC"
+ "value_trait": "ABC"
},
"sentAt": "2020-10-20T07:54:58.983Z"
},
@@ -3718,7 +4015,7 @@
"CHILD_KEY_102": "value_103"
},
"name_trait": "Company",
- "value_trait": "Comapny-ABC"
+ "value_trait": "ABC"
},
"sentAt": "2020-10-20T07:54:58.983Z"
},
@@ -3965,6 +4262,69 @@
}
}
},
+ {
+ "message": {
+ "anonymousId": "5d205961641ee6c5",
+ "channel": "mobile",
+ "context": {
+ "app": {
+ "build": "6",
+ "name": "Sample Kotlin",
+ "namespace": "com.example.testapp1mg",
+ "version": "1.2"
+ },
+ "device": {
+ "id": "5d205961641ee6c5",
+ "manufacturer": "Google",
+ "model": "Android SDK built for x86",
+ "name": "generic_x86",
+ "type": "Android"
+ },
+ "library": {
+ "name": "com.rudderstack.android.sdk.core",
+ "version": "1.7.0"
+ },
+ "locale": "en-US",
+ "network": {
+ "carrier": "Android",
+ "bluetooth": false,
+ "cellular": true,
+ "wifi": true
+ },
+ "os": {
+ "name": "Android",
+ "version": "7.1.1"
+ },
+ "screen": {
+ "density": 440,
+ "height": 2148,
+ "width": 1080
+ },
+ "sessionId": "1662393792",
+ "timezone": "Asia/Kolkata",
+ "traits": {
+ "anonymousId": "5d205961641ee6c5",
+ "id": "User Android",
+ "userId": "User Android"
+ },
+ "userAgent": "Dalvik/2.1.0 (Linux; U; Android 7.1.1; Android SDK built for x86 Build/NYC)"
+ },
+ "integrations": {
+ "All": true
+ },
+ "messageId": "1662393883248-509420bf-b812-4f8d-bdb2-8c811bfde87f",
+ "properties": {
+ },
+ "originalTimestamp": "2022-09-05T16:04:43.250Z",
+ "type": "screen",
+ "userId": "User Android"
+ },
+ "destination": {
+ "Config": {
+ "apiKey": "abcde"
+ }
+ }
+ },
{
"message": {
"channel": "web",
@@ -4185,7 +4545,7 @@
"CHILD_KEY_102": "value_103"
},
"name_trait": "Company",
- "value_trait": "Comapny-ABC"
+ "value_trait": "ABC"
},
"sentAt": "2020-10-20T07:54:58.983Z"
},
@@ -4464,7 +4824,6 @@
"search": "",
"title": "",
"url": "https://docs.rudderstack.com/destinations/amplitude",
- "category": "destination",
"initial_referrer": "https://docs.rudderstack.com",
"initial_referring_domain": "docs.rudderstack.com"
},
@@ -4474,15 +4833,14 @@
"event_id": 2
}
},
- "name": "ApplicationLoaded",
"sentAt": "2019-10-14T11:15:53.296Z"
},
"destination": {
"Config": {
"apiKey": "abcde",
- "useUserDefinedPageEventName": true,
+ "useUserDefinedPageEventName": false,
"userProvidedPageEventString": "Viewed {{context.page.title}} event."
}
}
}
-]
+]
\ No newline at end of file
diff --git a/test/__tests__/data/am_output.json b/test/__tests__/data/am_output.json
index b82df8ae0d..34471f4922 100644
--- a/test/__tests__/data/am_output.json
+++ b/test/__tests__/data/am_output.json
@@ -1,4 +1,138 @@
[
+ {
+ "error": "Event not present. Please send event field"
+ },
+ {
+ "error": "message type not supported"
+ },
+ {
+ "error": "No API Key is Found. Please Configure API key from dashbaord"
+ },
+ {
+ "version": "1",
+ "type": "REST",
+ "method": "POST",
+ "endpoint": "https://api2.amplitude.com/2/httpapi",
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "params": {},
+ "body": {
+ "JSON": {
+ "api_key": "abcde",
+ "events": [
+ {
+ "device_id": "50be5c78-6c3f-4b60-be84-97805a316fb1",
+ "library": "rudderstack",
+ "event_type": "Order Completed",
+ "insert_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9",
+ "event_properties": {
+ "tax": 2,
+ "total": 27.5,
+ "coupon": "hasbros",
+ "currency": "USD",
+ "discount": 2.5,
+ "order_id": "50314b8e9bcf000000000000",
+ "revenue_type": "Purchased",
+ "shipping": 3,
+ "subtotal": 22.5,
+ "affiliation": "Google Store",
+ "checkout_id": "fksdjfsdjfisjf9sdfjsd9f"
+ },
+ "revenueType": "Purchased",
+ "price": 48,
+ "quantity": 1,
+ "revenue": 48,
+ "time": 1597383030118,
+ "user_properties": {
+ "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1"
+ },
+ "session_id": -1
+ }
+ ],
+ "options": {
+ "min_id_length": 1
+ }
+ },
+ "XML": {},
+ "JSON_ARRAY": {},
+ "FORM": {}
+ },
+ "files": {},
+ "userId": "50be5c78-6c3f-4b60-be84-97805a316fb1"
+ },
+ {
+ "version": "1",
+ "type": "REST",
+ "method": "POST",
+ "endpoint": "https://api2.amplitude.com/2/httpapi",
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "params": {},
+ "body": {
+ "JSON": {
+ "api_key": "abcde",
+ "events": [
+ {
+ "device_id": "50be5c78-6c3f-4b60-be84-97805a316fb1",
+ "library": "rudderstack",
+ "event_type": "Order Completed",
+ "insert_id": "7208bbb6-2c4e-45bb-bf5b-ad426f3593e9",
+ "event_properties": {
+ "tax": 2,
+ "total": 27.5,
+ "coupon": "hasbros",
+ "currency": "USD",
+ "discount": 2.5,
+ "order_id": "50314b8e9bcf000000000000",
+ "products": [
+ {
+ "category": "Games",
+ "image_url": "https:///www.example.com/product/path.jpg",
+ "name": "Monopoly: 3rd Edition",
+ "price": 19,
+ "product_id": "507f1f77bcf86cd799439011",
+ "quantity": 1,
+ "sku": "45790-32",
+ "url": "https://www.example.com/product/path"
+ },
+ {
+ "category": "Games",
+ "name": "Uno Card Game",
+ "price": 3,
+ "product_id": "505bd76785ebb509fc183733",
+ "quantity": 2,
+ "sku": "46493-32"
+ }
+ ],
+ "shipping": 3,
+ "subtotal": 22.5,
+ "affiliation": "Google Store",
+ "checkout_id": "fksdjfsdjfisjf9sdfjsd9f"
+ },
+ "revenueType": "Purchased",
+ "price": 48,
+ "quantity": 1,
+ "revenue": 48,
+ "time": 1597383030118,
+ "user_properties": {
+ "anonymousId": "50be5c78-6c3f-4b60-be84-97805a316fb1"
+ },
+ "session_id": -1
+ }
+ ],
+ "options": {
+ "min_id_length": 1
+ }
+ },
+ "XML": {},
+ "JSON_ARRAY": {},
+ "FORM": {}
+ },
+ "files": {},
+ "userId": "50be5c78-6c3f-4b60-be84-97805a316fb1"
+ },
{
"version": "1",
"type": "REST",
@@ -21,7 +155,7 @@
"app_name": "RudderLabs JavaScript SDK",
"app_version": "1.0.0",
"language": "en-US",
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"insert_id": "84e26acc-56a5-4835-8233-591137fca468",
"ip": "0.0.0.0",
"user_properties": {
@@ -77,7 +211,7 @@
"app_name": "RudderLabs JavaScript SDK",
"app_version": "1.0.0",
"language": "en-US",
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"insert_id": "84e26acc-56a5-4835-8233-591137fca468",
"ip": "0.0.0.0",
"user_properties": {
@@ -137,7 +271,7 @@
"app_name": "RudderLabs JavaScript SDK",
"app_version": "1.0.0",
"language": "en-US",
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"event_type": "$identify",
"user_properties": {
"anonymousId": "123456",
@@ -202,7 +336,7 @@
"initial_referring_domain": "docs.rudderstack.com",
"initial_referrer": "https://docs.rudderstack.com"
},
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"ip": "1.1.1.1",
"time": 1571051718299,
"user_id": "12345",
@@ -261,7 +395,7 @@
"initial_referring_domain": "docs.rudderstack.com",
"initial_referrer": "https://docs.rudderstack.com"
},
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"ip": "1.1.1.1",
"groups": {
"Company": "ABC"
@@ -312,7 +446,7 @@
"app_version": "1.0.0",
"language": "en-US",
"event_type": "test track event",
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"event_properties": {
"user_actual_role": "system_admin",
"user_actual_id": 12345,
@@ -366,7 +500,7 @@
"app_name": "RudderLabs JavaScript SDK",
"app_version": "1.0.0",
"language": "en-US",
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"event_type": "$identify",
"user_properties": {
"anonymousId": "123456",
@@ -419,7 +553,7 @@
"timestamp": "2020-08-28 09:00:00"
},
"event_type": "$identify",
- "session_id": "1598597129",
+ "session_id": 1598597129,
"time": 0,
"user_id": "ubcdfghi0001"
}
@@ -450,7 +584,7 @@
"events": [
{
"device_id": "123456",
- "session_id": "1598597129",
+ "session_id": 1598597129,
"event_type": "$identify",
"library": "rudderstack",
"user_properties": {
@@ -555,6 +689,83 @@
"files": {},
"userId": "123456"
},
+ [
+ {
+ "version": "1",
+ "type": "REST",
+ "method": "POST",
+ "endpoint": "https://api2.amplitude.com/2/httpapi",
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "params": {},
+ "body": {
+ "JSON": {
+ "api_key": "abcde",
+ "events": [
+ {
+ "os_name": "Chrome",
+ "os_version": "85.0.4183.121",
+ "platform": "Web",
+ "library": "rudderstack",
+ "device_model": "Mac",
+ "device_id": "my-anonymous-id-new",
+ "app_name": "RudderLabs JavaScript SDK",
+ "app_version": "1.1.5",
+ "language": "en-US",
+ "event_type": "$identify",
+ "groups": {
+ "Company": "ABC"
+ },
+ "user_properties": {
+ "Company": "ABC",
+ "utm_content": "some content",
+ "utm_medium": "medium",
+ "utm_name": "some campaign",
+ "utm_source": "google",
+ "utm_term": "keyword",
+ "utm_test": "other value",
+ "initial_referring_domain": "docs.rudderstack.com",
+ "initial_referrer": "https://docs.rudderstack.com"
+ },
+ "time": 1603180498983,
+ "user_id": "sampleusrRudder3",
+ "session_id": -1
+ }
+ ],
+ "options": {
+ "min_id_length": 1
+ }
+ },
+ "XML": {},
+ "JSON_ARRAY": {},
+ "FORM": {}
+ },
+ "files": {},
+ "userId": "my-anonymous-id-new"
+ },
+ {
+ "version": "1",
+ "type": "REST",
+ "method": "POST",
+ "endpoint": "https://api2.amplitude.com/groupidentify",
+ "headers": {},
+ "params": {},
+ "body": {
+ "JSON": {},
+ "XML": {},
+ "JSON_ARRAY": {},
+ "FORM": {
+ "api_key": "abcde",
+ "identification": [
+ "{\"group_type\":\"Company\",\"group_value\":\"ABC\"}"
+ ]
+ }
+ },
+ "files": {},
+ "userId": "my-anonymous-id-new"
+ }
+ ],
[
{
"version": "1",
@@ -581,7 +792,7 @@
"language": "en-US",
"event_type": "$identify",
"user_properties": {
- "Company": "Comapny-ABC",
+ "Company": "ABC",
"utm_content": "some content",
"utm_medium": "medium",
"utm_name": "some campaign",
@@ -592,7 +803,7 @@
"initial_referrer": "https://docs.rudderstack.com"
},
"groups": {
- "Company": "Comapny-ABC"
+ "Company": "ABC"
},
"time": 1603180498983,
"user_id": "sampleusrRudder3",
@@ -624,7 +835,7 @@
"FORM": {
"api_key": "abcde",
"identification": [
- "{\"group_type\":\"Company\",\"group_value\":\"Comapny-ABC\",\"group_properties\":{\"KEY_3\":{\"CHILD_KEY_92\":\"value_95\",\"CHILD_KEY_102\":\"value_103\"},\"KEY_2\":{\"CHILD_KEY_92\":\"value_95\",\"CHILD_KEY_102\":\"value_103\"},\"name_trait\":\"Company\",\"value_trait\":\"Comapny-ABC\"}}"
+ "{\"group_type\":\"Company\",\"group_value\":\"ABC\",\"group_properties\":{\"KEY_3\":{\"CHILD_KEY_92\":\"value_95\",\"CHILD_KEY_102\":\"value_103\"},\"KEY_2\":{\"CHILD_KEY_92\":\"value_95\",\"CHILD_KEY_102\":\"value_103\"},\"name_trait\":\"Company\",\"value_trait\":\"ABC\"}}"
]
}
},
@@ -2244,7 +2455,7 @@
"event_type": "Order Completed",
"user_id": "userID123",
"revenueType": "Purchased",
- "price": 25,
+ "price": 25.0,
"quantity": 2,
"revenue": 48,
"time": 1597383030118,
@@ -2886,7 +3097,7 @@
"app_name": "RudderLabs JavaScript SDK",
"app_version": "1.0.0",
"language": "en-US",
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"event_type": "$identify",
"device_brand": "testBrand",
"device_manufacturer": "testManufacturer",
@@ -3031,7 +3242,7 @@
"app_name": "RudderLabs JavaScript SDK",
"app_version": "1.0.0",
"language": "en-US",
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"insert_id": "84e26acc-56a5-4835-8233-591137fca468",
"ip": "0.0.0.0",
"user_properties": {
@@ -3091,7 +3302,7 @@
"language": "en-US",
"event_type": "$identify",
"user_properties": {
- "Company": "Comapny-ABC",
+ "Company": "ABC",
"utm_content": "some content",
"utm_medium": "medium",
"utm_name": "some campaign",
@@ -3102,7 +3313,7 @@
"initial_referrer": "https://docs.rudderstack.com"
},
"groups": {
- "Company": "Comapny-ABC"
+ "Company": "ABC"
},
"time": 1603180498983,
"user_id": "sampleusrRudder3",
@@ -3134,7 +3345,7 @@
"FORM": {
"api_key": "abcde",
"identification": [
- "{\"group_type\":\"Company\",\"group_value\":\"Comapny-ABC\",\"group_properties\":{\"KEY_3\":{\"CHILD_KEY_92\":\"value_95\",\"CHILD_KEY_102\":\"value_103\"},\"KEY_2\":{\"CHILD_KEY_92\":\"value_95\",\"CHILD_KEY_102\":\"value_103\"},\"name_trait\":\"Company\",\"value_trait\":\"Comapny-ABC\"}}"
+ "{\"group_type\":\"Company\",\"group_value\":\"ABC\",\"group_properties\":{\"KEY_3\":{\"CHILD_KEY_92\":\"value_95\",\"CHILD_KEY_102\":\"value_103\"},\"KEY_2\":{\"CHILD_KEY_92\":\"value_95\",\"CHILD_KEY_102\":\"value_103\"},\"name_trait\":\"Company\",\"value_trait\":\"ABC\"}}"
]
}
},
@@ -3483,11 +3694,11 @@
"utm_content": "some content",
"utm_name": "some campaign",
"utm_test": "other value",
- "Company": "Comapny-ABC"
+ "Company": "ABC"
},
"event_type": "$identify",
"groups": {
- "Company": "Comapny-ABC"
+ "Company": "ABC"
},
"time": 1603180498983,
"user_id": "sampleusrRudder3",
@@ -3520,7 +3731,7 @@
"FORM": {
"api_key": "abcde",
"identification": [
- "{\"group_type\":\"Company\",\"group_value\":\"Comapny-ABC\",\"group_properties\":{\"KEY_3\":{\"CHILD_KEY_92\":\"value_95\",\"CHILD_KEY_102\":\"value_103\"},\"KEY_2\":{\"CHILD_KEY_92\":\"value_95\",\"CHILD_KEY_102\":\"value_103\"},\"name_trait\":\"Company\",\"value_trait\":\"Comapny-ABC\"}}"
+ "{\"group_type\":\"Company\",\"group_value\":\"ABC\",\"group_properties\":{\"KEY_3\":{\"CHILD_KEY_92\":\"value_95\",\"CHILD_KEY_102\":\"value_103\"},\"KEY_2\":{\"CHILD_KEY_92\":\"value_95\",\"CHILD_KEY_102\":\"value_103\"},\"name_trait\":\"Company\",\"value_trait\":\"ABC\"}}"
]
}
},
@@ -3603,7 +3814,7 @@
"initial_referring_domain": "docs.rudderstack.com",
"name": "ApplicationLoaded"
},
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"insert_id": "5e10d13a-bf9a-44bf-b884-43a9e591ea71",
"ip": "1.1.1.1",
"event_id": 2,
@@ -3702,6 +3913,56 @@
"files": {},
"userId": "5d205961641ee6c5"
},
+ {
+ "version": "1",
+ "type": "REST",
+ "method": "POST",
+ "endpoint": "https://api2.amplitude.com/2/httpapi",
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "params": {},
+ "body": {
+ "JSON": {
+ "api_key": "abcde",
+ "events": [
+ {
+ "os_name": "Android",
+ "os_version": "7.1.1",
+ "device_model": "Android SDK built for x86",
+ "device_manufacturer": "Google",
+ "device_id": "5d205961641ee6c5",
+ "carrier": "Android",
+ "app_name": "Sample Kotlin",
+ "app_version": "1.2",
+ "platform": "Android",
+ "language": "en-US",
+ "event_properties": {},
+ "insert_id": "1662393883248-509420bf-b812-4f8d-bdb2-8c811bfde87f",
+ "user_properties": {
+ "anonymousId": "5d205961641ee6c5",
+ "id": "User Android",
+ "userId": "User Android"
+ },
+ "event_type": "Viewed Screen",
+ "user_id": "User Android",
+ "device_brand": "Google",
+ "time": 1662393883250,
+ "session_id": 1662393792,
+ "library": "rudderstack"
+ }
+ ],
+ "options": {
+ "min_id_length": 1
+ }
+ },
+ "JSON_ARRAY": {},
+ "XML": {},
+ "FORM": {}
+ },
+ "files": {},
+ "userId": "5d205961641ee6c5"
+ },
{
"version": "1",
"type": "REST",
@@ -3741,7 +4002,7 @@
"event_type": "$identify",
"time": 1571043797562,
"user_id": "123456",
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": 1662393792,
"country": "India",
"city": "kolkata",
"library": "rudderstack"
@@ -3847,7 +4108,7 @@
"initial_referring_domain": "docs.rudderstack.com",
"name": "ApplicationLoaded"
},
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"insert_id": "5e10d13a-bf9a-44bf-b884-43a9e591ea71",
"ip": "1.1.1.1",
"event_id": 2,
@@ -3907,7 +4168,7 @@
"initial_referring_domain": "docs.rudderstack.com",
"name": "ApplicationLoaded"
},
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"insert_id": "5e10d13a-bf9a-44bf-b884-43a9e591ea71",
"ip": "1.1.1.1",
"event_id": 2,
@@ -3967,7 +4228,7 @@
"initial_referring_domain": "docs.rudderstack.com",
"name": "ApplicationLoaded"
},
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"insert_id": "5e10d13a-bf9a-44bf-b884-43a9e591ea71",
"ip": "1.1.1.1",
"event_id": 2,
@@ -4015,19 +4276,17 @@
"app_name": "RudderLabs JavaScript SDK",
"app_version": "1.0.0",
"language": "en-US",
- "event_type": "Viewed Home Page event.",
+ "event_type": "Viewed Page",
"event_properties": {
"path": "/destinations/amplitude",
"referrer": "",
"search": "",
"title": "",
"url": "https://docs.rudderstack.com/destinations/amplitude",
- "category": "destination",
"initial_referrer": "https://docs.rudderstack.com",
- "initial_referring_domain": "docs.rudderstack.com",
- "name": "ApplicationLoaded"
+ "initial_referring_domain": "docs.rudderstack.com"
},
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"insert_id": "5e10d13a-bf9a-44bf-b884-43a9e591ea71",
"ip": "1.1.1.1",
"event_id": 2,
@@ -4053,4 +4312,4 @@
"files": {},
"userId": "00000000000000000000000000"
}
-]
+]
\ No newline at end of file
diff --git a/test/__tests__/data/am_router_output.json b/test/__tests__/data/am_router_output.json
index 5c9e23840a..bfccb478b3 100644
--- a/test/__tests__/data/am_router_output.json
+++ b/test/__tests__/data/am_router_output.json
@@ -24,7 +24,7 @@
"app_name": "RudderLabs JavaScript SDK",
"app_version": "1.0.0",
"language": "en-US",
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"insert_id": "84e26acc-56a5-4835-8233-591137fca468",
"city": "kolkata",
"country": "India",
@@ -109,7 +109,7 @@
"initial_referring_domain": "docs.rudderstack.com",
"name": "ApplicationLoaded"
},
- "session_id": "3049dc4c-5a95-4ccd-a3e7-d74a7e411f22",
+ "session_id": -1,
"insert_id": "5e10d13a-bf9a-44bf-b884-43a9e591ea71",
"ip": "1.1.1.1",
"user_properties": {
diff --git a/test/__tests__/data/freshmarketer.json b/test/__tests__/data/freshmarketer.json
index 3d30841b30..390c0fb44e 100644
--- a/test/__tests__/data/freshmarketer.json
+++ b/test/__tests__/data/freshmarketer.json
@@ -5,7 +5,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "rudderstack-476952domain3105"
+ "domain": "rudderstack-476952domain3105.myfreshworks.com"
}
},
"message": {
@@ -94,7 +94,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "rudderstack-476952domain3105"
+ "domain": "rudderstack-476952domain3105.myfreshworks.com"
}
},
"message": {
@@ -183,7 +183,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "rudderstack-476952domain3105"
+ "domain": "rudderstack-476952domain3105.myfreshworks.com"
}
},
"message": {
@@ -248,7 +248,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "rudderstack-476952domain3105"
+ "domain": "rudderstack-476952domain3105.myfreshworks.com"
}
},
"message": {
@@ -312,7 +312,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
},
"message": {
@@ -422,7 +422,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
},
"message": {
@@ -491,7 +491,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
},
"message": {
@@ -558,7 +558,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
},
"message": {
@@ -627,7 +627,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
},
"message": {
@@ -760,7 +760,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -843,7 +843,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -927,7 +927,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1019,7 +1019,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1127,7 +1127,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1228,7 +1228,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1315,7 +1315,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1406,7 +1406,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1496,7 +1496,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1586,7 +1586,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1696,7 +1696,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1757,7 +1757,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1788,7 +1788,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1825,7 +1825,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1892,7 +1892,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1937,7 +1937,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1976,7 +1976,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -2043,7 +2043,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -2145,7 +2145,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -2232,7 +2232,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -2334,7 +2334,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -2427,7 +2427,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder",
+ "domain": "domain-rudder.myfreshworks.com",
"rudderEventsToFreshmarketerEvents": [
{
"from": "test_activity",
diff --git a/test/__tests__/data/freshmarketer_router_input.json b/test/__tests__/data/freshmarketer_router_input.json
index 0e05c7f5f8..2cc5ce58de 100644
--- a/test/__tests__/data/freshmarketer_router_input.json
+++ b/test/__tests__/data/freshmarketer_router_input.json
@@ -3,7 +3,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "rudderstack-476952domain3105"
+ "domain": "rudderstack-476952domain3105.myfreshworks.com"
}
},
"metadata": {
@@ -59,7 +59,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "rudderstack-476952domain3105"
+ "domain": "rudderstack-476952domain3105.myfreshworks.com"
}
},
"metadata": {
@@ -115,7 +115,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
},
"metadata": {
diff --git a/test/__tests__/data/freshmarketer_router_output.json b/test/__tests__/data/freshmarketer_router_output.json
index 01740cb626..3525e4bb16 100644
--- a/test/__tests__/data/freshmarketer_router_output.json
+++ b/test/__tests__/data/freshmarketer_router_output.json
@@ -43,7 +43,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "rudderstack-476952domain3105"
+ "domain": "rudderstack-476952domain3105.myfreshworks.com"
}
}
},
@@ -91,7 +91,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "rudderstack-476952domain3105"
+ "domain": "rudderstack-476952domain3105.myfreshworks.com"
}
}
},
@@ -156,7 +156,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
}
diff --git a/test/__tests__/data/freshsales.json b/test/__tests__/data/freshsales.json
index 2527e37b90..55193532f4 100644
--- a/test/__tests__/data/freshsales.json
+++ b/test/__tests__/data/freshsales.json
@@ -69,7 +69,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -90,7 +90,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "rudderstack-476952domain3105"
+ "domain": "rudderstack-476952domain3105.myfreshworks.com"
}
},
"message": {
@@ -179,7 +179,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "rudderstack-476952domain3105"
+ "domain": "rudderstack-476952domain3105.myfreshworks.com"
}
},
"message": {
@@ -268,7 +268,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "rudderstack-476952domain3105"
+ "domain": "rudderstack-476952domain3105.myfreshworks.com"
}
},
"message": {
@@ -356,7 +356,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "rudderstack-476952domain3105"
+ "domain": "rudderstack-476952domain3105.myfreshworks.com"
}
},
"message": {
@@ -421,7 +421,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
},
"message": {
@@ -531,7 +531,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
},
"message": {
@@ -600,7 +600,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
},
"message": {
@@ -667,7 +667,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
},
"message": {
@@ -736,7 +736,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
},
"message": {
@@ -869,7 +869,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -952,7 +952,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1036,7 +1036,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1128,7 +1128,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder",
+ "domain": "domain-rudder.myfreshworks.com",
"rudderEventsToFreshsalesEvents": [
{
"from": "test",
@@ -1244,7 +1244,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1345,7 +1345,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1432,7 +1432,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1523,7 +1523,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1613,7 +1613,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1703,7 +1703,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1813,7 +1813,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1874,7 +1874,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -1966,7 +1966,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -2053,7 +2053,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
@@ -2155,7 +2155,7 @@
"destination": {
"Config": {
"apiKey": "dummyApiKey",
- "domain": "domain-rudder"
+ "domain": "domain-rudder.myfreshworks.com"
}
}
},
diff --git a/test/__tests__/data/freshsales_router_input.json b/test/__tests__/data/freshsales_router_input.json
index 856a127f51..ea4b9887dd 100644
--- a/test/__tests__/data/freshsales_router_input.json
+++ b/test/__tests__/data/freshsales_router_input.json
@@ -66,7 +66,7 @@
},
"Config": {
"apiKey": "hrkjfergeferf",
- "domain": "rudderstack-479541159204968909"
+ "domain": "rudderstack-479541159204968909.myfreshworks.com"
},
"Enabled": true,
"Transformations": [],
diff --git a/test/__tests__/data/freshsales_router_output.json b/test/__tests__/data/freshsales_router_output.json
index 449d6eb45a..69d259ff00 100644
--- a/test/__tests__/data/freshsales_router_output.json
+++ b/test/__tests__/data/freshsales_router_output.json
@@ -72,7 +72,7 @@
},
"Config": {
"apiKey": "hrkjfergeferf",
- "domain": "rudderstack-479541159204968909"
+ "domain": "rudderstack-479541159204968909.myfreshworks.com"
},
"Enabled": true,
"Transformations": [],
diff --git a/test/integrations/destinations/tiktok_audience/processor/data.ts b/test/integrations/destinations/tiktok_audience/processor/data.ts
new file mode 100644
index 0000000000..a715aa2f72
--- /dev/null
+++ b/test/integrations/destinations/tiktok_audience/processor/data.ts
@@ -0,0 +1,854 @@
+export const data = [
+ {
+ "name": "tiktok_audience",
+ "description": "Test 1: Containing SHA256 traits only",
+ "feature": "processor",
+ "module": "destination",
+ "version": "v0",
+ "input": {
+ "request": {
+ "body": [
+ {
+ "message": {
+ "userId": "user 1",
+ "type": "audiencelist",
+ "properties": {
+ "listData": {
+ "add": [
+ {
+ "EMAIL_SHA256": "alex@email.com"
+ },
+ {
+ "EMAIL_SHA256": "amy@abc.com"
+ },
+ {
+ "EMAIL_SHA256": "van@abc.com"
+ }
+ ],
+ "remove": [
+ {
+ "EMAIL_SHA256": "alex@email.com"
+ },
+ {
+ "EMAIL_SHA256": "amy@abc.com"
+ },
+ {
+ "EMAIL_SHA256": "van@abc.com"
+ }
+ ]
+ }
+ },
+ "context": {
+ "ip": "14.5.67.21",
+ "library": {
+ "name": "http"
+ },
+ "externalId": [
+ {
+ "type": "TIKTOK_AUDIENCE-23856594064540489",
+ "identifierType": "EMAIL_SHA256"
+ }
+ ],
+ "destinationFields": "EMAIL_SHA256"
+ },
+ "timestamp": "2020-02-02T00:23:09.544Z"
+ },
+ "metadata": {
+ "jobId": 1,
+ "secret": {
+ "accessToken": "dummyAccessToken",
+ "advertiserIds": [
+ "dummyAdverTiserID"
+ ]
+ }
+ },
+ "destination": {
+ "DestinationDefinition": {
+ "Config": {
+ "cdkV2Enabled": true
+ }
+ },
+ "Config": {
+ "isHashRequired": true,
+ "registerDeviceOrBrowserApiKey": true,
+ "apiKey": "intercomApiKey",
+ "appId": "9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0",
+ "collectContext": false
+ }
+ }
+ }
+ ]
+ }
+ },
+ "output": {
+ "response": {
+ "status": 200,
+ "body": [
+ {
+ "output": {
+ "version": "1",
+ "type": "REST",
+ "method": "POST",
+ "endpoint": "https://business-api.tiktok.com/open_api/v1.3/segment/mapping/",
+ "headers": {
+ "Access-Token": "dummyAccessToken",
+ "Content-Type": "application/json"
+ },
+ "params": {},
+ "body": {
+ "JSON": {
+ "batch_data": [
+ [
+ {
+ "id": "ac0f1baec38a9ef3cfcb56db981df7d9bab2568c7f53ef3776d1c059ec58e72b",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ],
+ [
+ {
+ "id": "49eaeca26c878f268ad33af8cfa8194ca5b8b8e448b1c775bf9153a2de734579",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ],
+ [
+ {
+ "id": "2048acfa84a01121060ca2fc8a673a76d427176dc37224d4408c21973bd90e5c",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ]
+ ],
+ "id_schema": [
+ "EMAIL_SHA256"
+ ],
+ "advertiser_ids": [
+ "dummyAdverTiserID"
+ ],
+ "action": "add"
+ },
+ "JSON_ARRAY": {},
+ "XML": {},
+ "FORM": {}
+ },
+ "files": {},
+ "userId": ""
+ },
+ "metadata": {
+ "jobId": 1,
+ "secret": {
+ "accessToken": "dummyAccessToken",
+ "advertiserIds": [
+ "dummyAdverTiserID"
+ ]
+ }
+ },
+ "statusCode": 200
+ },
+ {
+ "output": {
+ "version": "1",
+ "type": "REST",
+ "method": "POST",
+ "endpoint": "https://business-api.tiktok.com/open_api/v1.3/segment/mapping/",
+ "headers": {
+ "Access-Token": "dummyAccessToken",
+ "Content-Type": "application/json"
+ },
+ "params": {},
+ "body": {
+ "JSON": {
+ "batch_data": [
+ [
+ {
+ "id": "ac0f1baec38a9ef3cfcb56db981df7d9bab2568c7f53ef3776d1c059ec58e72b",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ],
+ [
+ {
+ "id": "49eaeca26c878f268ad33af8cfa8194ca5b8b8e448b1c775bf9153a2de734579",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ],
+ [
+ {
+ "id": "2048acfa84a01121060ca2fc8a673a76d427176dc37224d4408c21973bd90e5c",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ]
+ ],
+ "id_schema": [
+ "EMAIL_SHA256"
+ ],
+ "advertiser_ids": [
+ "dummyAdverTiserID"
+ ],
+ "action": "delete"
+ },
+ "JSON_ARRAY": {},
+ "XML": {},
+ "FORM": {}
+ },
+ "files": {},
+ "userId": ""
+ },
+ "metadata": {
+ "jobId": 1,
+ "secret": {
+ "accessToken": "dummyAccessToken",
+ "advertiserIds": [
+ "dummyAdverTiserID"
+ ]
+ }
+ },
+ "statusCode": 200
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "tiktok_audience",
+ "description": "Test 2: Containing SHA256 and MD5 traits",
+ "feature": "processor",
+ "module": "destination",
+ "version": "v0",
+ "input": {
+ "request": {
+ "body": [
+ {
+ "message": {
+ "userId": "user 1",
+ "type": "audiencelist",
+ "properties": {
+ "listData": {
+ "add": [
+ {
+ "EMAIL_SHA256": "alex@email.com",
+ "AAID_MD5": "1234567"
+ },
+ {
+ "EMAIL_SHA256": "amy@abc.com",
+ "AAID_MD5": "1234568"
+ },
+ {
+ "EMAIL_SHA256": "van@abc.com",
+ "AAID_MD5": "1234569"
+ }
+ ],
+ "remove": [
+ {
+ "EMAIL_SHA256": "alex@email.com",
+ "AAID_MD5": "1234570"
+ },
+ {
+ "EMAIL_SHA256": "amy@abc.com",
+ "AAID_MD5": "1234571"
+ },
+ {
+ "EMAIL_SHA256": "van@abc.com",
+ "AAID_MD5": "1234572"
+ }
+ ]
+ }
+ },
+ "context": {
+ "ip": "14.5.67.21",
+ "library": {
+ "name": "http"
+ },
+ "externalId": [
+ {
+ "type": "TIKTOK_AUDIENCE-23856594064540489",
+ "identifierType": "EMAIL_SHA256"
+ }
+ ],
+ "destinationFields": "EMAIL_SHA256, AAID_MD5"
+ },
+ "timestamp": "2020-02-02T00:23:09.544Z"
+ },
+ "metadata": {
+ "jobId": 1,
+ "secret": {
+ "accessToken": "dummyAccessToken",
+ "advertiserIds": [
+ "dummyAdverTiserID"
+ ]
+ }
+ },
+ "destination": {
+ "DestinationDefinition": {
+ "Config": {
+ "cdkV2Enabled": true
+ }
+ },
+ "Config": {
+ "isHashRequired": true,
+ "registerDeviceOrBrowserApiKey": true,
+ "apiKey": "intercomApiKey",
+ "appId": "9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0",
+ "collectContext": false
+ }
+ }
+ }
+ ]
+ }
+ },
+ "output": {
+ "response": {
+ "status": 200,
+ "body": [
+ {
+ "output": {
+ "version": "1",
+ "type": "REST",
+ "method": "POST",
+ "endpoint": "https://business-api.tiktok.com/open_api/v1.3/segment/mapping/",
+ "headers": {
+ "Access-Token": "dummyAccessToken",
+ "Content-Type": "application/json"
+ },
+ "params": {},
+ "body": {
+ "JSON": {
+ "batch_data": [
+ [
+ {
+ "id": "ac0f1baec38a9ef3cfcb56db981df7d9bab2568c7f53ef3776d1c059ec58e72b",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {
+ "id": "fcea920f7412b5da7be0cf42b8c93759",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ],
+ [
+ {
+ "id": "49eaeca26c878f268ad33af8cfa8194ca5b8b8e448b1c775bf9153a2de734579",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {
+ "id": "fe743d8d97aa7dfc6c93ccdc2e749513",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ],
+ [
+ {
+ "id": "2048acfa84a01121060ca2fc8a673a76d427176dc37224d4408c21973bd90e5c",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {
+ "id": "e36a2f90240e9e84483504fd4a704452",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ]
+ ],
+ "id_schema": [
+ "EMAIL_SHA256",
+ "AAID_MD5"
+ ],
+ "advertiser_ids": [
+ "dummyAdverTiserID"
+ ],
+ "action": "add"
+ },
+ "JSON_ARRAY": {},
+ "XML": {},
+ "FORM": {}
+ },
+ "files": {},
+ "userId": ""
+ },
+ "metadata": {
+ "jobId": 1,
+ "secret": {
+ "accessToken": "dummyAccessToken",
+ "advertiserIds": [
+ "dummyAdverTiserID"
+ ]
+ }
+ },
+ "statusCode": 200
+ },
+ {
+ "output": {
+ "version": "1",
+ "type": "REST",
+ "method": "POST",
+ "endpoint": "https://business-api.tiktok.com/open_api/v1.3/segment/mapping/",
+ "headers": {
+ "Access-Token": "dummyAccessToken",
+ "Content-Type": "application/json"
+ },
+ "params": {},
+ "body": {
+ "JSON": {
+ "batch_data": [
+ [
+ {
+ "id": "ac0f1baec38a9ef3cfcb56db981df7d9bab2568c7f53ef3776d1c059ec58e72b",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {
+ "id": "c1abd65fea29d573ddef1bce925e3276",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ],
+ [
+ {
+ "id": "49eaeca26c878f268ad33af8cfa8194ca5b8b8e448b1c775bf9153a2de734579",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {
+ "id": "7298110702a080dfc6903f13333eb04a",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ],
+ [
+ {
+ "id": "2048acfa84a01121060ca2fc8a673a76d427176dc37224d4408c21973bd90e5c",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {
+ "id": "d9cb68b1fd3b9d32abc5f4cab8b42b68",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ]
+ ],
+ "id_schema": [
+ "EMAIL_SHA256",
+ "AAID_MD5"
+ ],
+ "advertiser_ids": [
+ "dummyAdverTiserID"
+ ],
+ "action": "delete"
+ },
+ "JSON_ARRAY": {},
+ "XML": {},
+ "FORM": {}
+ },
+ "files": {},
+ "userId": ""
+ },
+ "metadata": {
+ "jobId": 1,
+ "secret": {
+ "accessToken": "dummyAccessToken",
+ "advertiserIds": [
+ "dummyAdverTiserID"
+ ]
+ }
+ },
+ "statusCode": 200
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "tiktok_audience",
+ "description": "Test 3: Containing all possible traits",
+ "feature": "processor",
+ "module": "destination",
+ "version": "v0",
+ "input": {
+ "request": {
+ "body": [
+ {
+ "message": {
+ "userId": "user 1",
+ "type": "audiencelist",
+ "properties": {
+ "listData": {
+ "add": [
+ {
+ "EMAIL_SHA256": "alex@email.com",
+ "PHONE_SHA256": "+129988776655",
+ "IDFA_SHA256": "1234lkasfjdalj12321",
+ "AAID_SHA256": "000999OOOQQQQ",
+ "AAID_MD5": "000999OOOQQQQ",
+ "IDFA_MD5": "1234lkasfjdalj12321"
+ },
+ {
+ "EMAIL_SHA256": "amy@abc.com",
+ "PHONE_SHA256": "+129988776677",
+ "IDFA_SHA256": "1234lkasfjdalj114455",
+ "AAID_SHA256": "000999OOOPPPP",
+ "AAID_MD5": "000999OOOPPPP",
+ "IDFA_MD5": "1234lkasfjdalj114455"
+ }
+ ]
+ }
+ },
+ "context": {
+ "ip": "14.5.67.21",
+ "library": {
+ "name": "http"
+ },
+ "externalId": [
+ {
+ "type": "TIKTOK_AUDIENCE-23856594064540489",
+ "identifierType": "EMAIL_SHA256"
+ }
+ ],
+ "destinationFields": "EMAIL_SHA256, PHONE_SHA256, IDFA_SHA256, AAID_SHA256, AAID_MD, IDFA_MD5"
+ },
+ "timestamp": "2020-02-02T00:23:09.544Z"
+ },
+ "metadata": {
+ "jobId": 1,
+ "secret": {
+ "accessToken": "dummyAccessToken",
+ "advertiserIds": [
+ "dummyAdverTiserID"
+ ]
+ }
+ },
+ "destination": {
+ "DestinationDefinition": {
+ "Config": {
+ "cdkV2Enabled": true
+ }
+ },
+ "Config": {
+ "isHashRequired": true,
+ "registerDeviceOrBrowserApiKey": true,
+ "apiKey": "intercomApiKey",
+ "appId": "9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0",
+ "collectContext": false
+ }
+ }
+ }
+ ]
+ }
+ },
+ "output": {
+ "response": {
+ "status": 200,
+ "body": [
+ {
+ "output": {
+ "version": "1",
+ "type": "REST",
+ "method": "POST",
+ "endpoint": "https://business-api.tiktok.com/open_api/v1.3/segment/mapping/",
+ "headers": {
+ "Access-Token": "dummyAccessToken",
+ "Content-Type": "application/json"
+ },
+ "params": {},
+ "body": {
+ "JSON": {
+ "batch_data": [
+ [
+ {
+ "id": "ac0f1baec38a9ef3cfcb56db981df7d9bab2568c7f53ef3776d1c059ec58e72b",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {
+ "id": "31e78a3bf9ce2b43316f64fe883a531d6266938091e94e2f2480272481163dee",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {
+ "id": "0259f595f7172c8dd692a5c37b4d296939555f862aae8adb964391bdb65006ab",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {
+ "id": "b06fbe7a29f33576a792ba3df3c9bf838cd26ea88cf574285fa60dc0234a8485",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {},
+ {
+ "id": "32ee3d063320815a13e0058c2498ff76",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ],
+ [
+ {
+ "id": "49eaeca26c878f268ad33af8cfa8194ca5b8b8e448b1c775bf9153a2de734579",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {
+ "id": "fb40adc7debbf40e7b45b0a4a91886785dff1a28809276f95f1c44f7045f9b4d",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {
+ "id": "e6bbdf34c5f3472f31b2923a26811560a599233f3dea4c9971595c3bb7b1e8dc",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {
+ "id": "661125f7d337811256c5b55996b22c89047804dcec494db72659e4be71e03091",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {},
+ {
+ "id": "94162773066d6ae88b2658dc58ca2317",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ]
+ ],
+ "id_schema": [
+ "EMAIL_SHA256",
+ "PHONE_SHA256",
+ "IDFA_SHA256",
+ "AAID_SHA256",
+ "AAID_MD",
+ "IDFA_MD5"
+ ],
+ "advertiser_ids": [
+ "dummyAdverTiserID"
+ ],
+ "action": "add"
+ },
+ "JSON_ARRAY": {},
+ "XML": {},
+ "FORM": {}
+ },
+ "files": {},
+ "userId": ""
+ },
+ "metadata": {
+ "jobId": 1,
+ "secret": {
+ "accessToken": "dummyAccessToken",
+ "advertiserIds": [
+ "dummyAdverTiserID"
+ ]
+ }
+ },
+ "statusCode": 200
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "tiktok_audience",
+ "description": "Test 4: Considering some null values",
+ "feature": "processor",
+ "module": "destination",
+ "version": "v0",
+ "input": {
+ "request": {
+ "body": [
+ {
+ "message": {
+ "userId": "user 1",
+ "type": "audiencelist",
+ "properties": {
+ "listData": {
+ "add": [
+ {
+ "EMAIL_SHA256": "alex@email.com",
+ "PHONE_SHA256": "+129988776655",
+ "AAID_MD5": "000999OOOQQQQ",
+ "IDFA_MD5": "1234lkasfjdalj12321"
+ },
+ {
+ "EMAIL_SHA256": "amy@abc.com",
+ "AAID_SHA256": "000999OOOPPPP",
+ "AAID_MD5": "000999OOOPPPP",
+ "IDFA_MD5": "1234lkasfjdalj114455"
+ }
+ ]
+ }
+ },
+ "context": {
+ "ip": "14.5.67.21",
+ "library": {
+ "name": "http"
+ },
+ "externalId": [
+ {
+ "type": "TIKTOK_AUDIENCE-23856594064540489",
+ "identifierType": "EMAIL_SHA256"
+ }
+ ],
+ "destinationFields": "EMAIL_SHA256, PHONE_SHA256, IDFA_SHA256, AAID_SHA256, AAID_MD, IDFA_MD5"
+ },
+ "timestamp": "2020-02-02T00:23:09.544Z"
+ },
+ "metadata": {
+ "jobId": 1,
+ "secret": {
+ "accessToken": "dummyAccessToken",
+ "advertiserIds": [
+ "dummyAdverTiserID"
+ ]
+ }
+ },
+ "destination": {
+ "DestinationDefinition": {
+ "Config": {
+ "cdkV2Enabled": true
+ }
+ },
+ "Config": {
+ "isHashRequired": true,
+ "registerDeviceOrBrowserApiKey": true,
+ "apiKey": "intercomApiKey",
+ "appId": "9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0",
+ "collectContext": false
+ }
+ }
+ }
+ ]
+ }
+ },
+ "output": {
+ "response": {
+ "status": 200,
+ "body": [
+ {
+ "output": {
+ "version": "1",
+ "type": "REST",
+ "method": "POST",
+ "endpoint": "https://business-api.tiktok.com/open_api/v1.3/segment/mapping/",
+ "headers": {
+ "Access-Token": "dummyAccessToken",
+ "Content-Type": "application/json"
+ },
+ "params": {},
+ "body": {
+ "JSON": {
+ "batch_data": [
+ [
+ {
+ "id": "ac0f1baec38a9ef3cfcb56db981df7d9bab2568c7f53ef3776d1c059ec58e72b",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {
+ "id": "31e78a3bf9ce2b43316f64fe883a531d6266938091e94e2f2480272481163dee",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {},
+ {},
+ {},
+ {
+ "id": "32ee3d063320815a13e0058c2498ff76",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ],
+ [
+ {
+ "id": "49eaeca26c878f268ad33af8cfa8194ca5b8b8e448b1c775bf9153a2de734579",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {},
+ {},
+ {
+ "id": "661125f7d337811256c5b55996b22c89047804dcec494db72659e4be71e03091",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ },
+ {},
+ {
+ "id": "94162773066d6ae88b2658dc58ca2317",
+ "audience_ids": [
+ "23856594064540489"
+ ]
+ }
+ ]
+ ],
+ "id_schema": [
+ "EMAIL_SHA256",
+ "PHONE_SHA256",
+ "IDFA_SHA256",
+ "AAID_SHA256",
+ "AAID_MD",
+ "IDFA_MD5"
+ ],
+ "advertiser_ids": [
+ "dummyAdverTiserID"
+ ],
+ "action": "add"
+ },
+ "JSON_ARRAY": {},
+ "XML": {},
+ "FORM": {}
+ },
+ "files": {},
+ "userId": ""
+ },
+ "metadata": {
+ "jobId": 1,
+ "secret": {
+ "accessToken": "dummyAccessToken",
+ "advertiserIds": [
+ "dummyAdverTiserID"
+ ]
+ }
+ },
+ "statusCode": 200
+ }
+ ]
+ }
+ }
+ }
+]
\ No newline at end of file
diff --git a/test/integrations/destinations/tiktok_audience/router/data.ts b/test/integrations/destinations/tiktok_audience/router/data.ts
new file mode 100644
index 0000000000..c8a8b93d30
--- /dev/null
+++ b/test/integrations/destinations/tiktok_audience/router/data.ts
@@ -0,0 +1,833 @@
+export const data = [
+ {
+ name: 'tiktok_audience',
+ description: 'Multiple jobs with different metadata',
+ feature: 'router',
+ module: 'destination',
+ version: 'v0',
+ input: {
+ request: {
+ body: {
+ input: [
+ {
+ message: {
+ userId: 'user 1',
+ type: 'audiencelist',
+ properties: {
+ listData: {
+ add: [
+ {
+ EMAIL_SHA256: 'alex@email.com',
+ },
+ {
+ EMAIL_SHA256: 'amy@abc.com',
+ },
+ {
+ EMAIL_SHA256: 'van@abc.com',
+ },
+ ],
+ remove: [
+ {
+ EMAIL_SHA256: 'alex@email.com',
+ },
+ {
+ EMAIL_SHA256: 'amy@abc.com',
+ },
+ {
+ EMAIL_SHA256: 'van@abc.com',
+ },
+ ],
+ },
+ },
+ context: {
+ ip: '14.5.67.21',
+ library: {
+ name: 'http',
+ },
+ externalId: [
+ {
+ type: 'TIKTOK_AUDIENCE-23856594064540489',
+ identifierType: 'EMAIL_SHA256',
+ },
+ ],
+ destinationFields: 'EMAIL_SHA256',
+ },
+ timestamp: '2020-02-02T00:23:09.544Z',
+ },
+ metadata: {
+ jobId: 1,
+ secret: {
+ accessToken: 'dummyAccessToken',
+ advertiserIds: ['dummyAdverTiserID'],
+ },
+ },
+ destination: {
+ DestinationDefinition: {
+ Config: {
+ cdkV2Enabled: true,
+ },
+ },
+ Config: {
+ isHashRequired: true,
+ registerDeviceOrBrowserApiKey: true,
+ apiKey: 'intercomApiKey',
+ appId: '9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0',
+ collectContext: false,
+ },
+ },
+ },
+ {
+ message: {
+ userId: 'user 1',
+ type: 'audiencelist',
+ properties: {
+ listData: {
+ add: [
+ {
+ EMAIL_SHA256: 'alex@email.com',
+ AAID_MD5: '1234567',
+ },
+ {
+ EMAIL_SHA256: 'amy@abc.com',
+ AAID_MD5: '1234568',
+ },
+ {
+ EMAIL_SHA256: 'van@abc.com',
+ AAID_MD5: '1234569',
+ },
+ ],
+ remove: [
+ {
+ EMAIL_SHA256: 'alex@email.com',
+ AAID_MD5: '1234570',
+ },
+ {
+ EMAIL_SHA256: 'amy@abc.com',
+ AAID_MD5: '1234571',
+ },
+ {
+ EMAIL_SHA256: 'van@abc.com',
+ AAID_MD5: '1234572',
+ },
+ ],
+ },
+ },
+ context: {
+ ip: '14.5.67.21',
+ library: {
+ name: 'http',
+ },
+ externalId: [
+ {
+ type: 'TIKTOK_AUDIENCE-23856594064540489',
+ identifierType: 'EMAIL_SHA256',
+ },
+ ],
+ destinationFields: 'EMAIL_SHA256, AAID_MD5',
+ },
+ timestamp: '2020-02-02T00:23:09.544Z',
+ },
+ metadata: {
+ jobId: 2,
+ secret: {
+ accessToken: 'dummyAccessToken',
+ advertiserIds: ['dummyAdverTiserID'],
+ },
+ },
+ destination: {
+ DestinationDefinition: {
+ Config: {
+ cdkV2Enabled: true,
+ },
+ },
+ Config: {
+ isHashRequired: true,
+ registerDeviceOrBrowserApiKey: true,
+ apiKey: 'intercomApiKey',
+ appId: '9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0',
+ collectContext: false,
+ },
+ },
+ },
+ {
+ message: {
+ userId: 'user 1',
+ type: 'audiencelist',
+ properties: {
+ listData: {
+ add: [
+ {
+ EMAIL_SHA256: 'alex@email.com',
+ PHONE_SHA256: '+129988776655',
+ IDFA_SHA256: '1234lkasfjdalj12321',
+ AAID_SHA256: '000999OOOQQQQ',
+ AAID_MD5: '000999OOOQQQQ',
+ IDFA_MD5: '1234lkasfjdalj12321',
+ },
+ {
+ EMAIL_SHA256: 'amy@abc.com',
+ PHONE_SHA256: '+129988776677',
+ IDFA_SHA256: '1234lkasfjdalj114455',
+ AAID_SHA256: '000999OOOPPPP',
+ AAID_MD5: '000999OOOPPPP',
+ IDFA_MD5: '1234lkasfjdalj114455',
+ },
+ ],
+ },
+ },
+ context: {
+ ip: '14.5.67.21',
+ library: {
+ name: 'http',
+ },
+ externalId: [
+ {
+ type: 'TIKTOK_AUDIENCE-23856594064540489',
+ identifierType: 'EMAIL_SHA256',
+ },
+ ],
+ destinationFields:
+ 'EMAIL_SHA256, PHONE_SHA256, IDFA_SHA256, AAID_SHA256, AAID_MD, IDFA_MD5',
+ },
+ timestamp: '2020-02-02T00:23:09.544Z',
+ },
+ metadata: {
+ jobId: 3,
+ secret: {
+ accessToken: 'dummyAccessToken',
+ advertiserIds: ['dummyAdverTiserID'],
+ },
+ },
+ destination: {
+ DestinationDefinition: {
+ Config: {
+ cdkV2Enabled: true,
+ },
+ },
+ Config: {
+ isHashRequired: true,
+ registerDeviceOrBrowserApiKey: true,
+ apiKey: 'intercomApiKey',
+ appId: '9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0',
+ collectContext: false,
+ },
+ },
+ },
+ {
+ message: {
+ userId: 'user 1',
+ type: 'audiencelist',
+ properties: {
+ listData: {
+ add: [
+ {
+ EMAIL_SHA256: 'alex@email.com',
+ PHONE_SHA256: '+129988776655',
+ AAID_MD5: '000999OOOQQQQ',
+ IDFA_MD5: '1234lkasfjdalj12321',
+ },
+ {
+ EMAIL_SHA256: 'amy@abc.com',
+ AAID_SHA256: '000999OOOPPPP',
+ AAID_MD5: '000999OOOPPPP',
+ IDFA_MD5: '1234lkasfjdalj114455',
+ },
+ ],
+ },
+ },
+ context: {
+ ip: '14.5.67.21',
+ library: {
+ name: 'http',
+ },
+ externalId: [
+ {
+ type: 'TIKTOK_AUDIENCE-23856594064540489',
+ identifierType: 'EMAIL_SHA256',
+ },
+ ],
+ destinationFields:
+ 'EMAIL_SHA256, PHONE_SHA256, IDFA_SHA256, AAID_SHA256, AAID_MD, IDFA_MD5',
+ },
+ timestamp: '2020-02-02T00:23:09.544Z',
+ },
+ metadata: {
+ jobId: 4,
+ secret: {
+ accessToken: 'dummyAccessToken',
+ advertiserIds: ['dummyAdverTiserID'],
+ },
+ },
+ destination: {
+ DestinationDefinition: {
+ Config: {
+ cdkV2Enabled: true,
+ },
+ },
+ Config: {
+ isHashRequired: true,
+ registerDeviceOrBrowserApiKey: true,
+ apiKey: 'intercomApiKey',
+ appId: '9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0',
+ collectContext: false,
+ },
+ },
+ },
+ {
+ message: {
+ userId: 'user 1',
+ properties: {
+ listData: {
+ add: [
+ {
+ EMAIL_SHA256: 'alex@email.com',
+ PHONE_SHA256: '+129988776655',
+ AAID_MD5: '000999OOOQQQQ',
+ IDFA_MD5: '1234lkasfjdalj12321',
+ },
+ {
+ EMAIL_SHA256: 'amy@abc.com',
+ AAID_SHA256: '000999OOOPPPP',
+ AAID_MD5: '000999OOOPPPP',
+ IDFA_MD5: '1234lkasfjdalj114455',
+ },
+ ],
+ },
+ },
+ context: {
+ ip: '14.5.67.21',
+ library: {
+ name: 'http',
+ },
+ externalId: [
+ {
+ type: 'TIKTOK_AUDIENCE-23856594064540489',
+ identifierType: 'EMAIL_SHA256',
+ },
+ ],
+ destinationFields:
+ 'EMAIL_SHA256, PHONE_SHA256, IDFA_SHA256, AAID_SHA256, AAID_MD, IDFA_MD5',
+ },
+ timestamp: '2020-02-02T00:23:09.544Z',
+ },
+ metadata: {
+ jobId: 1524545,
+ secret: {
+ accessToken: 'dummyAccessToken',
+ advertiserIds: ['dummyAdverTiserID'],
+ },
+ },
+ destination: {
+ DestinationDefinition: {
+ Config: {
+ cdkV2Enabled: true,
+ },
+ },
+ Config: {
+ isHashRequired: true,
+ registerDeviceOrBrowserApiKey: true,
+ apiKey: 'intercomApiKey',
+ appId: '9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0',
+ collectContext: false,
+ },
+ },
+ },
+ ],
+ destType: 'tiktok_audience',
+ },
+ method: 'POST',
+ },
+ },
+ output: {
+ response: {
+ status: 200,
+ body: {
+ output: [
+ {
+ error: 'message Type is not present. Aborting message.',
+ batched: false,
+ destination: {
+ DestinationDefinition: {
+ Config: {
+ cdkV2Enabled: true,
+ },
+ },
+ Config: {
+ isHashRequired: true,
+ registerDeviceOrBrowserApiKey: true,
+ apiKey: 'intercomApiKey',
+ appId: '9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0',
+ collectContext: false,
+ },
+ },
+ metadata: [
+ {
+ jobId: 1524545,
+ secret: {
+ accessToken: 'dummyAccessToken',
+ advertiserIds: ['dummyAdverTiserID'],
+ },
+ },
+ ],
+ statTags: {
+ destType: 'TIKTOK_AUDIENCE',
+ errorCategory: 'dataValidation',
+ errorType: 'instrumentation',
+ feature: 'router',
+ implementation: 'cdkV2',
+ module: 'destination',
+ },
+ statusCode: 400,
+ },
+ {
+ batchedRequest: [
+ {
+ version: '1',
+ type: 'REST',
+ method: 'POST',
+ endpoint: 'https://business-api.tiktok.com/open_api/v1.3/segment/mapping/',
+ headers: {
+ 'Access-Token': 'dummyAccessToken',
+ 'Content-Type': 'application/json',
+ },
+ params: {},
+ body: {
+ JSON: {
+ batch_data: [
+ [
+ {
+ id: 'ac0f1baec38a9ef3cfcb56db981df7d9bab2568c7f53ef3776d1c059ec58e72b',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ [
+ {
+ id: '49eaeca26c878f268ad33af8cfa8194ca5b8b8e448b1c775bf9153a2de734579',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ [
+ {
+ id: '2048acfa84a01121060ca2fc8a673a76d427176dc37224d4408c21973bd90e5c',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ ],
+ id_schema: ['EMAIL_SHA256'],
+ advertiser_ids: ['dummyAdverTiserID'],
+ action: 'add',
+ },
+ JSON_ARRAY: {},
+ XML: {},
+ FORM: {},
+ },
+ files: {},
+ },
+ {
+ version: '1',
+ type: 'REST',
+ method: 'POST',
+ endpoint: 'https://business-api.tiktok.com/open_api/v1.3/segment/mapping/',
+ headers: {
+ 'Access-Token': 'dummyAccessToken',
+ 'Content-Type': 'application/json',
+ },
+ params: {},
+ body: {
+ JSON: {
+ batch_data: [
+ [
+ {
+ id: 'ac0f1baec38a9ef3cfcb56db981df7d9bab2568c7f53ef3776d1c059ec58e72b',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ [
+ {
+ id: '49eaeca26c878f268ad33af8cfa8194ca5b8b8e448b1c775bf9153a2de734579',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ [
+ {
+ id: '2048acfa84a01121060ca2fc8a673a76d427176dc37224d4408c21973bd90e5c',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ ],
+ id_schema: ['EMAIL_SHA256'],
+ advertiser_ids: ['dummyAdverTiserID'],
+ action: 'delete',
+ },
+ JSON_ARRAY: {},
+ XML: {},
+ FORM: {},
+ },
+ files: {},
+ },
+ ],
+ batched: true,
+ destination: {
+ DestinationDefinition: {
+ Config: {
+ cdkV2Enabled: true,
+ },
+ },
+ Config: {
+ isHashRequired: true,
+ registerDeviceOrBrowserApiKey: true,
+ apiKey: 'intercomApiKey',
+ appId: '9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0',
+ collectContext: false,
+ },
+ },
+ metadata: [
+ {
+ jobId: 1,
+ secret: {
+ accessToken: 'dummyAccessToken',
+ advertiserIds: ['dummyAdverTiserID'],
+ },
+ },
+ ],
+ statusCode: 200,
+ },
+ {
+ batchedRequest: [
+ {
+ version: '1',
+ type: 'REST',
+ method: 'POST',
+ endpoint: 'https://business-api.tiktok.com/open_api/v1.3/segment/mapping/',
+ headers: {
+ 'Access-Token': 'dummyAccessToken',
+ 'Content-Type': 'application/json',
+ },
+ params: {},
+ body: {
+ JSON: {
+ batch_data: [
+ [
+ {
+ id: 'ac0f1baec38a9ef3cfcb56db981df7d9bab2568c7f53ef3776d1c059ec58e72b',
+ audience_ids: ['23856594064540489'],
+ },
+ {
+ id: 'fcea920f7412b5da7be0cf42b8c93759',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ [
+ {
+ id: '49eaeca26c878f268ad33af8cfa8194ca5b8b8e448b1c775bf9153a2de734579',
+ audience_ids: ['23856594064540489'],
+ },
+ {
+ id: 'fe743d8d97aa7dfc6c93ccdc2e749513',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ [
+ {
+ id: '2048acfa84a01121060ca2fc8a673a76d427176dc37224d4408c21973bd90e5c',
+ audience_ids: ['23856594064540489'],
+ },
+ {
+ id: 'e36a2f90240e9e84483504fd4a704452',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ ],
+ id_schema: ['EMAIL_SHA256', 'AAID_MD5'],
+ advertiser_ids: ['dummyAdverTiserID'],
+ action: 'add',
+ },
+ JSON_ARRAY: {},
+ XML: {},
+ FORM: {},
+ },
+ files: {},
+ },
+ {
+ version: '1',
+ type: 'REST',
+ method: 'POST',
+ endpoint: 'https://business-api.tiktok.com/open_api/v1.3/segment/mapping/',
+ headers: {
+ 'Access-Token': 'dummyAccessToken',
+ 'Content-Type': 'application/json',
+ },
+ params: {},
+ body: {
+ JSON: {
+ batch_data: [
+ [
+ {
+ id: 'ac0f1baec38a9ef3cfcb56db981df7d9bab2568c7f53ef3776d1c059ec58e72b',
+ audience_ids: ['23856594064540489'],
+ },
+ {
+ id: 'c1abd65fea29d573ddef1bce925e3276',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ [
+ {
+ id: '49eaeca26c878f268ad33af8cfa8194ca5b8b8e448b1c775bf9153a2de734579',
+ audience_ids: ['23856594064540489'],
+ },
+ {
+ id: '7298110702a080dfc6903f13333eb04a',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ [
+ {
+ id: '2048acfa84a01121060ca2fc8a673a76d427176dc37224d4408c21973bd90e5c',
+ audience_ids: ['23856594064540489'],
+ },
+ {
+ id: 'd9cb68b1fd3b9d32abc5f4cab8b42b68',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ ],
+ id_schema: ['EMAIL_SHA256', 'AAID_MD5'],
+ advertiser_ids: ['dummyAdverTiserID'],
+ action: 'delete',
+ },
+ JSON_ARRAY: {},
+ XML: {},
+ FORM: {},
+ },
+ files: {},
+ },
+ ],
+ batched: true,
+ destination: {
+ DestinationDefinition: {
+ Config: {
+ cdkV2Enabled: true,
+ },
+ },
+ Config: {
+ isHashRequired: true,
+ registerDeviceOrBrowserApiKey: true,
+ apiKey: 'intercomApiKey',
+ appId: '9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0',
+ collectContext: false,
+ },
+ },
+ metadata: [
+ {
+ jobId: 2,
+ secret: {
+ accessToken: 'dummyAccessToken',
+ advertiserIds: ['dummyAdverTiserID'],
+ },
+ },
+ ],
+ statusCode: 200,
+ },
+ {
+ batchedRequest: {
+ version: '1',
+ type: 'REST',
+ method: 'POST',
+ endpoint: 'https://business-api.tiktok.com/open_api/v1.3/segment/mapping/',
+ headers: {
+ 'Access-Token': 'dummyAccessToken',
+ 'Content-Type': 'application/json',
+ },
+ params: {},
+ body: {
+ JSON: {
+ batch_data: [
+ [
+ {
+ id: 'ac0f1baec38a9ef3cfcb56db981df7d9bab2568c7f53ef3776d1c059ec58e72b',
+ audience_ids: ['23856594064540489'],
+ },
+ {
+ id: '31e78a3bf9ce2b43316f64fe883a531d6266938091e94e2f2480272481163dee',
+ audience_ids: ['23856594064540489'],
+ },
+ {
+ id: '0259f595f7172c8dd692a5c37b4d296939555f862aae8adb964391bdb65006ab',
+ audience_ids: ['23856594064540489'],
+ },
+ {
+ id: 'b06fbe7a29f33576a792ba3df3c9bf838cd26ea88cf574285fa60dc0234a8485',
+ audience_ids: ['23856594064540489'],
+ },
+ {},
+ {
+ id: '32ee3d063320815a13e0058c2498ff76',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ [
+ {
+ id: '49eaeca26c878f268ad33af8cfa8194ca5b8b8e448b1c775bf9153a2de734579',
+ audience_ids: ['23856594064540489'],
+ },
+ {
+ id: 'fb40adc7debbf40e7b45b0a4a91886785dff1a28809276f95f1c44f7045f9b4d',
+ audience_ids: ['23856594064540489'],
+ },
+ {
+ id: 'e6bbdf34c5f3472f31b2923a26811560a599233f3dea4c9971595c3bb7b1e8dc',
+ audience_ids: ['23856594064540489'],
+ },
+ {
+ id: '661125f7d337811256c5b55996b22c89047804dcec494db72659e4be71e03091',
+ audience_ids: ['23856594064540489'],
+ },
+ {},
+ {
+ id: '94162773066d6ae88b2658dc58ca2317',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ ],
+ id_schema: [
+ 'EMAIL_SHA256',
+ 'PHONE_SHA256',
+ 'IDFA_SHA256',
+ 'AAID_SHA256',
+ 'AAID_MD',
+ 'IDFA_MD5',
+ ],
+ advertiser_ids: ['dummyAdverTiserID'],
+ action: 'add',
+ },
+ JSON_ARRAY: {},
+ XML: {},
+ FORM: {},
+ },
+ files: {},
+ },
+ batched: true,
+ destination: {
+ DestinationDefinition: {
+ Config: {
+ cdkV2Enabled: true,
+ },
+ },
+ Config: {
+ isHashRequired: true,
+ registerDeviceOrBrowserApiKey: true,
+ apiKey: 'intercomApiKey',
+ appId: '9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0',
+ collectContext: false,
+ },
+ },
+ metadata: [
+ {
+ jobId: 3,
+ secret: {
+ accessToken: 'dummyAccessToken',
+ advertiserIds: ['dummyAdverTiserID'],
+ },
+ },
+ ],
+ statusCode: 200,
+ },
+ {
+ batchedRequest: {
+ version: '1',
+ type: 'REST',
+ method: 'POST',
+ endpoint: 'https://business-api.tiktok.com/open_api/v1.3/segment/mapping/',
+ headers: {
+ 'Access-Token': 'dummyAccessToken',
+ 'Content-Type': 'application/json',
+ },
+ params: {},
+ body: {
+ JSON: {
+ batch_data: [
+ [
+ {
+ id: 'ac0f1baec38a9ef3cfcb56db981df7d9bab2568c7f53ef3776d1c059ec58e72b',
+ audience_ids: ['23856594064540489'],
+ },
+ {
+ id: '31e78a3bf9ce2b43316f64fe883a531d6266938091e94e2f2480272481163dee',
+ audience_ids: ['23856594064540489'],
+ },
+ {},
+ {},
+ {},
+ {
+ id: '32ee3d063320815a13e0058c2498ff76',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ [
+ {
+ id: '49eaeca26c878f268ad33af8cfa8194ca5b8b8e448b1c775bf9153a2de734579',
+ audience_ids: ['23856594064540489'],
+ },
+ {},
+ {},
+ {
+ id: '661125f7d337811256c5b55996b22c89047804dcec494db72659e4be71e03091',
+ audience_ids: ['23856594064540489'],
+ },
+ {},
+ {
+ id: '94162773066d6ae88b2658dc58ca2317',
+ audience_ids: ['23856594064540489'],
+ },
+ ],
+ ],
+ id_schema: [
+ 'EMAIL_SHA256',
+ 'PHONE_SHA256',
+ 'IDFA_SHA256',
+ 'AAID_SHA256',
+ 'AAID_MD',
+ 'IDFA_MD5',
+ ],
+ advertiser_ids: ['dummyAdverTiserID'],
+ action: 'add',
+ },
+ JSON_ARRAY: {},
+ XML: {},
+ FORM: {},
+ },
+ files: {},
+ },
+ batched: true,
+ destination: {
+ DestinationDefinition: {
+ Config: {
+ cdkV2Enabled: true,
+ },
+ },
+ Config: {
+ isHashRequired: true,
+ registerDeviceOrBrowserApiKey: true,
+ apiKey: 'intercomApiKey',
+ appId: '9e9cdea1-78fa-4829-a9b2-5d7f7e96d1a0',
+ collectContext: false,
+ },
+ },
+ metadata: [
+ {
+ jobId: 4,
+ secret: {
+ accessToken: 'dummyAccessToken',
+ advertiserIds: ['dummyAdverTiserID'],
+ },
+ },
+ ],
+ statusCode: 200,
+ },
+ ],
+ },
+ },
+ },
+ },
+];
diff --git a/test/integrations/sources/revenuecat/data.ts b/test/integrations/sources/revenuecat/data.ts
new file mode 100644
index 0000000000..4963781763
--- /dev/null
+++ b/test/integrations/sources/revenuecat/data.ts
@@ -0,0 +1,286 @@
+export const data = [
+ {
+ name: 'revenuecat',
+ description: 'Simple track call',
+ module: 'source',
+ version: 'v0',
+ input: {
+ request: {
+ body: [
+ {
+ api_version: '1.0',
+ event: {
+ aliases: [
+ 'f8e14f51-0c76-49ba-8d67-c229f1875dd9',
+ '389ad6dd-bb40-4c03-9471-1353da2d55ec',
+ ],
+ app_user_id: 'f8e14f51-0c76-49ba-8d67-c229f1875dd9',
+ commission_percentage: null,
+ country_code: 'US',
+ currency: null,
+ entitlement_id: null,
+ entitlement_ids: null,
+ environment: 'SANDBOX',
+ event_timestamp_ms: 1698617217232,
+ expiration_at_ms: 1698624417232,
+ id: '8CF0CD6C-CAF3-41FB-968A-661938235AF0',
+ is_family_share: null,
+ offer_code: null,
+ original_app_user_id: 'f8e14f51-0c76-49ba-8d67-c229f1875dd9',
+ original_transaction_id: null,
+ period_type: 'NORMAL',
+ presented_offering_id: null,
+ price: null,
+ price_in_purchased_currency: null,
+ product_id: 'test_product',
+ purchased_at_ms: 1698617217232,
+ store: 'APP_STORE',
+ subscriber_attributes: {
+ $displayName: {
+ updated_at_ms: 1698617217232,
+ value: 'Mister Mistoffelees',
+ },
+ $email: {
+ updated_at_ms: 1698617217232,
+ value: 'tuxedo@revenuecat.com',
+ },
+ $phoneNumber: {
+ updated_at_ms: 1698617217232,
+ value: '+19795551234',
+ },
+ my_custom_attribute_1: {
+ updated_at_ms: 1698617217232,
+ value: 'catnip',
+ },
+ },
+ takehome_percentage: null,
+ tax_percentage: null,
+ transaction_id: null,
+ type: 'TEST',
+ },
+ },
+ ],
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ },
+ pathSuffix: '',
+ },
+ output: {
+ response: {
+ status: 200,
+ body: [
+ {
+ output: {
+ batch: [
+ {
+ context: {
+ library: {
+ name: 'unknown',
+ version: 'unknown',
+ },
+ integration: {
+ name: 'RevenueCat',
+ },
+ externalId: [
+ {
+ type: 'revenuecatAppUserId',
+ id: 'f8e14f51-0c76-49ba-8d67-c229f1875dd9',
+ },
+ ],
+ },
+ integrations: {
+ RevenueCat: false,
+ },
+ type: 'track',
+ properties: {
+ aliases: [
+ 'f8e14f51-0c76-49ba-8d67-c229f1875dd9',
+ '389ad6dd-bb40-4c03-9471-1353da2d55ec',
+ ],
+ appUserId: 'f8e14f51-0c76-49ba-8d67-c229f1875dd9',
+ commissionPercentage: null,
+ countryCode: 'US',
+ currency: null,
+ entitlementId: null,
+ entitlementIds: null,
+ environment: 'SANDBOX',
+ eventTimestampMs: 1698617217232,
+ expirationAtMs: 1698624417232,
+ id: '8CF0CD6C-CAF3-41FB-968A-661938235AF0',
+ isFamilyShare: null,
+ offerCode: null,
+ originalAppUserId: 'f8e14f51-0c76-49ba-8d67-c229f1875dd9',
+ originalTransactionId: null,
+ periodType: 'NORMAL',
+ presentedOfferingId: null,
+ price: null,
+ priceInPurchasedCurrency: null,
+ productId: 'test_product',
+ purchasedAtMs: 1698617217232,
+ store: 'APP_STORE',
+ subscriberAttributes: {
+ $displayName: {
+ updated_at_ms: 1698617217232,
+ value: 'Mister Mistoffelees',
+ },
+ $email: {
+ updated_at_ms: 1698617217232,
+ value: 'tuxedo@revenuecat.com',
+ },
+ $phoneNumber: {
+ updated_at_ms: 1698617217232,
+ value: '+19795551234',
+ },
+ my_custom_attribute_1: {
+ updated_at_ms: 1698617217232,
+ value: 'catnip',
+ },
+ },
+ takehomePercentage: null,
+ taxPercentage: null,
+ transactionId: null,
+ type: 'TEST',
+ },
+ event: 'TEST',
+ messageId: '8CF0CD6C-CAF3-41FB-968A-661938235AF0',
+ originalTimestamp: '2023-10-29T22:06:57.232Z',
+ sentAt: '2023-10-29T22:06:57.232Z',
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ },
+ {
+ name: 'revenuecat',
+ description: 'Initial purchase event',
+ module: 'source',
+ version: 'v0',
+ input: {
+ request: {
+ body: [
+ {
+ api_version: '1.0',
+ event: {
+ aliases: ['yourCustomerAliasedID', 'yourCustomerAliasedID'],
+ app_id: 'yourAppID',
+ app_user_id: 'yourCustomerAppUserID',
+ commission_percentage: 0.3,
+ country_code: 'US',
+ currency: 'USD',
+ entitlement_id: 'pro_cat',
+ entitlement_ids: ['pro_cat'],
+ environment: 'PRODUCTION',
+ event_timestamp_ms: 1591121855319,
+ expiration_at_ms: 1591726653000,
+ id: 'UniqueIdentifierOfEvent',
+ is_family_share: false,
+ offer_code: 'free_month',
+ original_app_user_id: 'OriginalAppUserID',
+ original_transaction_id: '1530648507000',
+ period_type: 'NORMAL',
+ presented_offering_id: 'OfferingID',
+ price: 2.49,
+ price_in_purchased_currency: 2.49,
+ product_id: 'onemonth_no_trial',
+ purchased_at_ms: 1591121853000,
+ store: 'APP_STORE',
+ subscriber_attributes: {
+ '$Favorite Cat': {
+ updated_at_ms: 1581121853000,
+ value: 'Garfield',
+ },
+ },
+ takehome_percentage: 0.7,
+ tax_percentage: 0.3,
+ transaction_id: '170000869511114',
+ type: 'INITIAL_PURCHASE',
+ },
+ },
+ ],
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ },
+ pathSuffix: '',
+ },
+ output: {
+ response: {
+ status: 200,
+ body: [
+ {
+ output: {
+ batch: [
+ {
+ context: {
+ library: {
+ name: 'unknown',
+ version: 'unknown',
+ },
+ integration: {
+ name: 'RevenueCat',
+ },
+ externalId: [
+ {
+ type: 'revenuecatAppUserId',
+ id: 'yourCustomerAppUserID',
+ },
+ ],
+ },
+ integrations: {
+ RevenueCat: false,
+ },
+ type: 'track',
+ properties: {
+ aliases: ['yourCustomerAliasedID', 'yourCustomerAliasedID'],
+ appId: 'yourAppID',
+ appUserId: 'yourCustomerAppUserID',
+ commissionPercentage: 0.3,
+ countryCode: 'US',
+ currency: 'USD',
+ entitlementId: 'pro_cat',
+ entitlementIds: ['pro_cat'],
+ environment: 'PRODUCTION',
+ eventTimestampMs: 1591121855319,
+ expirationAtMs: 1591726653000,
+ id: 'UniqueIdentifierOfEvent',
+ isFamilyShare: false,
+ offerCode: 'free_month',
+ originalAppUserId: 'OriginalAppUserID',
+ originalTransactionId: '1530648507000',
+ periodType: 'NORMAL',
+ presentedOfferingId: 'OfferingID',
+ price: 2.49,
+ priceInPurchasedCurrency: 2.49,
+ productId: 'onemonth_no_trial',
+ purchasedAtMs: 1591121853000,
+ store: 'APP_STORE',
+ subscriberAttributes: {
+ '$Favorite Cat': {
+ updated_at_ms: 1581121853000,
+ value: 'Garfield',
+ },
+ },
+ takehomePercentage: 0.7,
+ taxPercentage: 0.3,
+ transactionId: '170000869511114',
+ type: 'INITIAL_PURCHASE',
+ },
+ event: 'INITIAL_PURCHASE',
+ messageId: 'UniqueIdentifierOfEvent',
+ originalTimestamp: '2020-06-02T18:17:35.319Z',
+ sentAt: '2020-06-02T18:17:35.319Z',
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ },
+];