Skip to content

Commit

Permalink
Merge branch 'develop' into feat.upgrade-to-node-v20-int-1547
Browse files Browse the repository at this point in the history
  • Loading branch information
saikumarrs authored Feb 16, 2024
2 parents 08a44e6 + 9683161 commit baa7146
Show file tree
Hide file tree
Showing 21 changed files with 1,084 additions and 85 deletions.
2 changes: 2 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ N/A

N/A

@coderabbitai review

<hr>

### Developer checklist
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ dist

# Others
**/.DS_Store

.dccache

.idea

Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
<p align="center">
⚠️ Docker image for rudder-transformer has been moved to new org <a href="https://hub.docker.com/r/rudderstack/rudder-transformer/tags">rudderstack/rudder-transformer</a>
<br/><br/>
</p>

[![codecov](https://codecov.io/gh/rudderlabs/rudder-transformer/branch/develop/graph/badge.svg?token=G24OON85SB)](https://codecov.io/gh/rudderlabs/rudder-transformer)

# RudderStack Transformer
Expand Down
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"@ndhoule/extend": "^2.0.0",
"@pyroscope/nodejs": "^0.2.6",
"@rudderstack/integrations-lib": "^0.2.2",
"@rudderstack/workflow-engine": "^0.6.9",
"@rudderstack/workflow-engine": "^0.7.2",
"ajv": "^8.12.0",
"ajv-draft-04": "^1.0.0",
"ajv-formats": "^2.1.1",
Expand Down
15 changes: 11 additions & 4 deletions src/cdk/v2/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,20 @@ export async function getWorkflowEngine(

const workflowEnginePromiseMap = new Map();

export function getCachedWorkflowEngine(
export async function getCachedWorkflowEngine(
destName: string,
feature: string,
bindings: Record<string, unknown> = {},
): WorkflowEngine {
): Promise<WorkflowEngine> {
// Create a new instance of the engine for the destination if needed
// TODO: Use cache to avoid long living engine objects
workflowEnginePromiseMap[destName] = workflowEnginePromiseMap[destName] || new Map();
if (!workflowEnginePromiseMap[destName][feature]) {
workflowEnginePromiseMap[destName][feature] = getWorkflowEngine(destName, feature, bindings);
workflowEnginePromiseMap[destName][feature] = await getWorkflowEngine(
destName,
feature,
bindings,
);
}
return workflowEnginePromiseMap[destName][feature];
}
Expand Down Expand Up @@ -97,5 +101,8 @@ export function executeStep(
): Promise<StepOutput> {
return workflowEngine
.getStepExecutor(stepName)
.execute(input, Object.assign(workflowEngine.bindings, getEmptyExecutionBindings(), bindings));
.execute(
input,
Object.assign(workflowEngine.getBindings(), getEmptyExecutionBindings(), bindings),
);
}
15 changes: 11 additions & 4 deletions src/v0/destinations/af/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,15 @@ function getEventValueForUnIdentifiedTrackEvent(message) {
return { eventValue };
}

function getEventValueMapFromMappingJson(message, mappingJson, isMultiSupport) {
function getEventValueMapFromMappingJson(message, mappingJson, isMultiSupport, addPropertiesAtRoot) {
let eventValue = {};
set(eventValue, 'properties', message.properties);

if (addPropertiesAtRoot) {
eventValue = message.properties;
} else {
set(eventValue, 'properties', message.properties);
}

const sourceKeys = Object.keys(mappingJson);
sourceKeys.forEach((sourceKey) => {
set(eventValue, mappingJson[sourceKey], get(message, sourceKey));
Expand Down Expand Up @@ -160,7 +166,7 @@ function processNonTrackEvents(message, eventName) {
return payload;
}

function processEventTypeTrack(message) {
function processEventTypeTrack(message, addPropertiesAtRoot) {
let isMultiSupport = true;
const evType = message.event && message.event.toLowerCase();
let category = ConfigCategory.DEFAULT;
Expand All @@ -184,6 +190,7 @@ function processEventTypeTrack(message) {
message,
mappingConfig[category.name],
isMultiSupport,
addPropertiesAtRoot,
);
payload.eventName = message.event;
payload.eventCurrency = message?.properties?.currency;
Expand All @@ -196,7 +203,7 @@ function processSingleMessage(message, destination) {
let payload;
switch (messageType) {
case EventType.TRACK: {
payload = processEventTypeTrack(message);
payload = processEventTypeTrack(message, destination.Config.addPropertiesAtRoot);
break;
}
case EventType.SCREEN: {
Expand Down
7 changes: 4 additions & 3 deletions src/v0/destinations/am/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -614,16 +614,16 @@ const processSingleMessage = (message, destination) => {
case EventType.PAGE:
if (useUserDefinedPageEventName) {
const getMessagePath = userProvidedPageEventString
.substring(
?.substring(
userProvidedPageEventString.indexOf('{') + 2,
userProvidedPageEventString.indexOf('}'),
)
.trim();
evType =
userProvidedPageEventString.trim() === ''
userProvidedPageEventString?.trim() === ''
? name
: userProvidedPageEventString
.trim()
?.trim()
.replaceAll(/{{([^{}]+)}}/g, get(message, getMessagePath));
} else {
evType = `Viewed ${name || get(message, CATEGORY_KEY) || ''} Page`;
Expand Down Expand Up @@ -701,6 +701,7 @@ const processSingleMessage = (message, destination) => {
logger.debug('could not determine type');
throw new InstrumentationError('message type not supported');
}
AMUtils.validateEventType(evType);
return responseBuilderSimple(
groupInfo,
payloadObjectName,
Expand Down
33 changes: 32 additions & 1 deletion src/v0/destinations/am/util.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { getUnsetObj } = require('./utils');
const { getUnsetObj, validateEventType } = require('./utils');

describe('getUnsetObj', () => {
it("should return undefined when 'message.integrations.Amplitude.fieldsToUnset' is not array", () => {
Expand Down Expand Up @@ -64,3 +64,34 @@ describe('getUnsetObj', () => {
expect(result).toBeUndefined();
});
});


describe('validateEventType', () => {

it('should validate event type when it is valid with only page name given', () => {
expect(() => {
validateEventType('Home Page');
}).not.toThrow();
});

it('should throw an error when event type is null', () => {
expect(() => {
validateEventType(null);
}).toThrow('Event type is missing. Please send it under `event.type`. For page/screen events, send it under `event.name`');
});

it('should throw an error when event type is undefined', () => {
expect(() => {
validateEventType(undefined);
}).toThrow('Event type is missing. Please send it under `event.type`. For page/screen events, send it under `event.name`');
});

// Function receives an empty string as event type
it('should throw an error when event type is an empty string', () => {
expect(() => {
validateEventType('');
}).toThrow('Event type is missing. Please send it under `event.type`. For page/screen events, send it under `event.name`');
});

});

15 changes: 15 additions & 0 deletions src/v0/destinations/am/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// populate these dest keys
const get = require('get-value');
const uaParser = require('@amplitude/ua-parser-js');
const { InstrumentationError } = require('@rudderstack/integrations-lib');
const logger = require('../../../logger');
const { isDefinedAndNotNull } = require('../../util');

Expand Down Expand Up @@ -108,6 +109,19 @@ const getUnsetObj = (message) => {

return unsetObject;
};

/**
* Check for evType as in some cases, like when the page name is absent,
* either the template depends only on the event.name or there is no template provided by user
* @param {*} evType
*/
const validateEventType = (evType) => {
if (!isDefinedAndNotNull(evType) || (typeof evType === "string" && evType.length ===0)) {
throw new InstrumentationError(
'Event type is missing. Please send it under `event.type`. For page/screen events, send it under `event.name`',
);
}
};
module.exports = {
getOSName,
getOSVersion,
Expand All @@ -117,4 +131,5 @@ module.exports = {
getBrand,
getEventId,
getUnsetObj,
validateEventType
};
55 changes: 30 additions & 25 deletions src/v0/destinations/custify/deleteUsers.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,41 @@ const userDeletionHandler = async (userAttributes, config) => {
}

const { apiKey } = config;
const { userId } = userAttributes;

if (!apiKey) {
throw new ConfigurationError('api key for deletion not present', 400);
}
if (!userId) {
throw new InstrumentationError('User id for deletion not present', 400);
}
const requestUrl = `https://api.custify.com/people?user_id=${userId}`;
const requestOptions = {
headers: {
Authorization: `Bearer ${apiKey}`,
},
};
await Promise.all(
userAttributes.map(async (userAttr) => {
const { userId } = userAttr;
if (!userId) {
throw new InstrumentationError('User id for deletion not present', 400);
}
// Reference: https://docs.custify.com/#tag/People/paths/~1people/delete
const requestUrl = `https://api.custify.com/people?user_id=${userId}`;
const requestOptions = {
headers: {
Authorization: `Bearer ${apiKey}`,
},
};

const deletionResponse = await httpDELETE(requestUrl, requestOptions, {
destType: 'custify',
feature: 'deleteUsers',
});
const processedDeletionRequest = processAxiosResponse(deletionResponse);
if (processedDeletionRequest.status !== 200 && processedDeletionRequest.status !== 404) {
throw new NetworkError(
JSON.stringify(processedDeletionRequest.response) || 'Error while deleting user',
processedDeletionRequest.status,
{
[tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(processedDeletionRequest.status),
},
deletionResponse,
);
}
const deletionResponse = await httpDELETE(requestUrl, requestOptions, {
destType: 'custify',
feature: 'deleteUsers',
});
const processedDeletionRequest = processAxiosResponse(deletionResponse);
if (processedDeletionRequest.status !== 200 && processedDeletionRequest.status !== 404) {
throw new NetworkError(
JSON.stringify(processedDeletionRequest.response) || 'Error while deleting user',
processedDeletionRequest.status,
{
[tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(processedDeletionRequest.status),
},
deletionResponse,
);
}
}),
);

return { statusCode: 200, status: 'successful' };
};
Expand Down
4 changes: 2 additions & 2 deletions src/v0/destinations/ga4/networkHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ const responseHandler = (destinationResponse, dest) => {
const { description, validationCode, fieldPath } = response.validationMessages[0];
throw new NetworkError(
`Validation Server Response Handler:: Validation Error for ${dest} of field path :${fieldPath} | ${validationCode}-${description}`,
status,
400,
{
[tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status),
[tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(400),
},
response?.validationMessages[0]?.description,
);
Expand Down
2 changes: 1 addition & 1 deletion src/v0/destinations/tiktok_ads/transformV2.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const getTrackResponsePayload = (message, destConfig, event) => {
}

// if contents is not present but we have properties.products present which has fields with superset of contents fields
if (payload.properties && !payload.properties.contents && message.properties.products) {
if (!payload.properties?.contents && message.properties?.products) {
// retreiving data from products only when contents is not present
payload.properties.contents = getContents(message, false);
}
Expand Down
20 changes: 16 additions & 4 deletions src/v0/destinations/tiktok_ads_offline_events/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,24 @@ const CONFIG_CATEGORIES = {
const PARTNER_NAME = 'RudderStack';

const EVENT_NAME_MAPPING = {
'addpaymentinfo': 'AddPaymentInfo',
'addtocart': 'AddToCart',
'addtowishlist': 'AddToWishlist',
'checkout started': 'InitiateCheckout',
'checkout step completed': 'CompletePayment',
contact: 'Contact',
submitform: 'SubmitForm',
subscribe: 'Subscribe',
'clickbutton': 'ClickButton',
'completeregistration': 'CompleteRegistration',
'contact': 'Contact',
'download': 'Download',
'order completed': 'PlaceAnOrder',
'payment info entered': 'AddPaymentInfo',
'product added': 'AddToCart',
'product added to wishlist': 'AddToWishlist',
'search': 'Search',
'submitform': 'SubmitForm',
'subscribe': 'Subscribe',
'viewcontent': 'ViewContent',
};

const MAPPING_CONFIG = getMappingConfig(CONFIG_CATEGORIES, __dirname);

module.exports = {
Expand Down
2 changes: 1 addition & 1 deletion src/v0/util/facebookUtils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ const getContentType = (message, defaultValue, categoryToContent, destinationNam
return integrationsObj.contentType;
}

let { category } = properties;
let { category } = properties || {};
if (!category) {
const { products } = properties;
if (products && products.length > 0 && Array.isArray(products) && isObject(products[0])) {
Expand Down
Loading

0 comments on commit baa7146

Please sign in to comment.